From 77b04a0428ea83d000634f06eb3b37ee92d9f866 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 22 Jan 2016 12:42:47 +0000 Subject: drm/i915: More use of the cached LRC state Since: commit 82352e908acd36d7244c75a008c9f27a2ced44d5 Author: Tvrtko Ursulin Date: Fri Jan 15 17:12:45 2016 +0000 drm/i915: Cache LRC state page in the context and: commit 0eb973d31d0aadb6bc801fd6d796afecbbfc3d5b Author: Tvrtko Ursulin Date: Fri Jan 15 15:10:28 2016 +0000 drm/i915: Cache ringbuffer GTT VMA We can also remove the ring buffer start updates on every context update since the address will not change for the duration of the LRC pin. For GuC we can remove the update altogether because it only cares about the ring buffer start. Signed-off-by: Tvrtko Ursulin Cc: Alex Dai Cc: Dave Gordon Cc: Chris Wilson Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1453466567-33369-1-git-send-email-tvrtko.ursulin@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 51ae5c1..7a7e1e5 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -560,29 +560,6 @@ static int guc_add_workqueue_item(struct i915_guc_client *gc, return 0; } -#define CTX_RING_BUFFER_START 0x08 - -/* Update the ringbuffer pointer in a saved context image */ -static void lr_context_update(struct drm_i915_gem_request *rq) -{ - enum intel_ring_id ring_id = rq->ring->id; - struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring_id].state; - struct drm_i915_gem_object *rb_obj = rq->ringbuf->obj; - struct page *page; - uint32_t *reg_state; - - BUG_ON(!ctx_obj); - WARN_ON(!i915_gem_obj_is_pinned(ctx_obj)); - WARN_ON(!i915_gem_obj_is_pinned(rb_obj)); - - page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN); - reg_state = kmap_atomic(page); - - reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj); - - kunmap_atomic(reg_state); -} - /** * i915_guc_submit() - Submit commands through GuC * @client: the guc client where commands will go through @@ -597,10 +574,6 @@ int i915_guc_submit(struct i915_guc_client *client, enum intel_ring_id ring_id = rq->ring->id; int q_ret, b_ret; - /* Need this because of the deferred pin ctx and ring */ - /* Shall we move this right after ring is pinned? */ - lr_context_update(rq); - q_ret = guc_add_workqueue_item(client, rq); if (q_ret == 0) b_ret = guc_ring_doorbell(client); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 73d4347..116c10f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -393,7 +393,6 @@ static int execlists_update_context(struct drm_i915_gem_request *rq) uint32_t *reg_state = rq->ctx->engine[ring->id].lrc_reg_state; reg_state[CTX_RING_TAIL+1] = rq->tail; - reg_state[CTX_RING_BUFFER_START+1] = rq->ringbuf->vma->node.start; if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) { /* True 32b PPGTT with dynamic page allocation: update PDP @@ -1067,6 +1066,7 @@ static int intel_lr_context_do_pin(struct intel_engine_cs *ring, struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state; struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; struct page *lrc_state_page; + uint32_t *lrc_reg_state; int ret; WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); @@ -1088,7 +1088,9 @@ static int intel_lr_context_do_pin(struct intel_engine_cs *ring, ctx->engine[ring->id].lrc_vma = i915_gem_obj_to_ggtt(ctx_obj); intel_lr_context_descriptor_update(ctx, ring); - ctx->engine[ring->id].lrc_reg_state = kmap(lrc_state_page); + lrc_reg_state = kmap(lrc_state_page); + lrc_reg_state[CTX_RING_BUFFER_START+1] = ringbuf->vma->node.start; + ctx->engine[ring->id].lrc_reg_state = lrc_reg_state; ctx_obj->dirty = true; /* Invalidate GuC TLB. */ -- cgit v0.10.2 From 397097b026190309f4eec630db0e2f5ba498542e Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Sat, 23 Jan 2016 11:58:14 -0800 Subject: drm/i915/guc: Decouple GuC engine id from ring id Previously GuC uses ring id as engine id because of same definition. But this is not true since this commit: commit de1add360522c876c25ef2bbbbab1c94bdb509ab Author: Tvrtko Ursulin Date: Fri Jan 15 15:12:50 2016 +0000 drm/i915: Decouple execbuf uAPI from internal implementation Added GuC engine id into GuC interface to decouple it from ring id used by driver. v2: Keep ring name print out in debugfs; using for_each_ring() where possible to keep driver consistent. (Chris W.) Signed-off-by: Alex Dai Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1453579094-29860-1-git-send-email-yu.dai@intel.com diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c5db235..cea1844 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2463,9 +2463,9 @@ static void i915_guc_client_info(struct seq_file *m, for_each_ring(ring, dev_priv, i) { seq_printf(m, "\tSubmissions: %llu %s\n", - client->submissions[i], + client->submissions[ring->guc_id], ring->name); - tot += client->submissions[i]; + tot += client->submissions[ring->guc_id]; } seq_printf(m, "\tTotal: %llu\n", tot); } @@ -2502,10 +2502,10 @@ static int i915_guc_info(struct seq_file *m, void *data) seq_printf(m, "\nGuC submissions:\n"); for_each_ring(ring, dev_priv, i) { - seq_printf(m, "\t%-24s: %10llu, last seqno 0x%08x %9d\n", - ring->name, guc.submissions[i], - guc.last_seqno[i], guc.last_seqno[i]); - total += guc.submissions[i]; + seq_printf(m, "\t%-24s: %10llu, last seqno 0x%08x\n", + ring->name, guc.submissions[ring->guc_id], + guc.last_seqno[ring->guc_id]); + total += guc.submissions[ring->guc_id]; } seq_printf(m, "\t%s: %llu\n", "Total", total); diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 7a7e1e5..d7543ef 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -376,6 +376,8 @@ static void guc_init_proc_desc(struct intel_guc *guc, static void guc_init_ctx_desc(struct intel_guc *guc, struct i915_guc_client *client) { + struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct intel_engine_cs *ring; struct intel_context *ctx = client->owner; struct guc_context_desc desc; struct sg_table *sg; @@ -388,10 +390,8 @@ static void guc_init_ctx_desc(struct intel_guc *guc, desc.priority = client->priority; desc.db_id = client->doorbell_id; - for (i = 0; i < I915_NUM_RINGS; i++) { - struct guc_execlist_context *lrc = &desc.lrc[i]; - struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf; - struct intel_engine_cs *ring; + for_each_ring(ring, dev_priv, i) { + struct guc_execlist_context *lrc = &desc.lrc[ring->guc_id]; struct drm_i915_gem_object *obj; uint64_t ctx_desc; @@ -406,7 +406,6 @@ static void guc_init_ctx_desc(struct intel_guc *guc, if (!obj) break; /* XXX: continue? */ - ring = ringbuf->ring; ctx_desc = intel_lr_context_descriptor(ctx, ring); lrc->context_desc = (u32)ctx_desc; @@ -414,16 +413,16 @@ static void guc_init_ctx_desc(struct intel_guc *guc, lrc->ring_lcra = i915_gem_obj_ggtt_offset(obj) + LRC_STATE_PN * PAGE_SIZE; lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) | - (ring->id << GUC_ELC_ENGINE_OFFSET); + (ring->guc_id << GUC_ELC_ENGINE_OFFSET); - obj = ringbuf->obj; + obj = ctx->engine[i].ringbuf->obj; lrc->ring_begin = i915_gem_obj_ggtt_offset(obj); lrc->ring_end = lrc->ring_begin + obj->base.size - 1; lrc->ring_next_free_location = lrc->ring_begin; lrc->ring_current_tail_pointer_value = 0; - desc.engines_used |= (1 << ring->id); + desc.engines_used |= (1 << ring->guc_id); } WARN_ON(desc.engines_used == 0); @@ -510,7 +509,6 @@ int i915_guc_wq_check_space(struct i915_guc_client *gc) static int guc_add_workqueue_item(struct i915_guc_client *gc, struct drm_i915_gem_request *rq) { - enum intel_ring_id ring_id = rq->ring->id; struct guc_wq_item *wqi; void *base; u32 tail, wq_len, wq_off, space; @@ -544,7 +542,7 @@ static int guc_add_workqueue_item(struct i915_guc_client *gc, wq_len = sizeof(struct guc_wq_item) / sizeof(u32) - 1; wqi->header = WQ_TYPE_INORDER | (wq_len << WQ_LEN_SHIFT) | - (ring_id << WQ_TARGET_SHIFT) | + (rq->ring->guc_id << WQ_TARGET_SHIFT) | WQ_NO_WCFLUSH_WAIT; /* The GuC wants only the low-order word of the context descriptor */ @@ -571,14 +569,14 @@ int i915_guc_submit(struct i915_guc_client *client, struct drm_i915_gem_request *rq) { struct intel_guc *guc = client->guc; - enum intel_ring_id ring_id = rq->ring->id; + unsigned int engine_id = rq->ring->guc_id; int q_ret, b_ret; q_ret = guc_add_workqueue_item(client, rq); if (q_ret == 0) b_ret = guc_ring_doorbell(client); - client->submissions[ring_id] += 1; + client->submissions[engine_id] += 1; if (q_ret) { client->q_fail += 1; client->retcode = q_ret; @@ -588,8 +586,8 @@ int i915_guc_submit(struct i915_guc_client *client, } else { client->retcode = 0; } - guc->submissions[ring_id] += 1; - guc->last_seqno[ring_id] = rq->seqno; + guc->submissions[engine_id] += 1; + guc->last_seqno[engine_id] = rq->seqno; return q_ret; } @@ -821,7 +819,7 @@ static void init_guc_policies(struct guc_policies *policies) policies->max_num_work_items = POLICY_MAX_NUM_WI; for (p = 0; p < GUC_CTX_PRIORITY_NUM; p++) { - for (i = 0; i < I915_NUM_RINGS; i++) { + for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) { policy = &policies->policy[p][i]; policy->execution_quantum = 1000000; @@ -873,7 +871,7 @@ static void guc_create_ads(struct intel_guc *guc) ads->golden_context_lrca = ring->status_page.gfx_addr; for_each_ring(ring, dev_priv, i) - ads->eng_state_size[i] = intel_lr_context_size(ring); + ads->eng_state_size[ring->guc_id] = intel_lr_context_size(ring); /* GuC scheduling policies */ policies = (void *)ads + sizeof(struct guc_ads); @@ -885,12 +883,12 @@ static void guc_create_ads(struct intel_guc *guc) /* MMIO reg state */ reg_state = (void *)policies + sizeof(struct guc_policies); - for (i = 0; i < I915_NUM_RINGS; i++) { - reg_state->mmio_white_list[i].mmio_start = - dev_priv->ring[i].mmio_base + GUC_MMIO_WHITE_LIST_START; + for_each_ring(ring, dev_priv, i) { + reg_state->mmio_white_list[ring->guc_id].mmio_start = + ring->mmio_base + GUC_MMIO_WHITE_LIST_START; /* Nothing to be saved or restored for now. */ - reg_state->mmio_white_list[i].count = 0; + reg_state->mmio_white_list[ring->guc_id].count = 0; } ads->reg_state_addr = ads->scheduler_policies + diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 045b149..73002e9 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -46,7 +46,7 @@ struct i915_guc_client { uint32_t wq_head; /* GuC submission statistics & status */ - uint64_t submissions[I915_NUM_RINGS]; + uint64_t submissions[GUC_MAX_ENGINES_NUM]; uint32_t q_fail; uint32_t b_fail; int retcode; @@ -106,8 +106,8 @@ struct intel_guc { uint32_t action_fail; /* Total number of failures */ int32_t action_err; /* Last error code */ - uint64_t submissions[I915_NUM_RINGS]; - uint32_t last_seqno[I915_NUM_RINGS]; + uint64_t submissions[GUC_MAX_ENGINES_NUM]; + uint32_t last_seqno[GUC_MAX_ENGINES_NUM]; }; /* intel_guc_loader.c */ diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 1856a47..2de57ff 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -44,6 +44,13 @@ #define GUC_MAX_GPU_CONTEXTS 1024 #define GUC_INVALID_CTX_ID GUC_MAX_GPU_CONTEXTS +#define GUC_RENDER_ENGINE 0 +#define GUC_VIDEO_ENGINE 1 +#define GUC_BLITTER_ENGINE 2 +#define GUC_VIDEOENHANCE_ENGINE 3 +#define GUC_VIDEO_ENGINE2 4 +#define GUC_MAX_ENGINES_NUM (GUC_VIDEO_ENGINE2 + 1) + /* Work queue item header definitions */ #define WQ_STATUS_ACTIVE 1 #define WQ_STATUS_SUSPENDED 2 @@ -285,7 +292,7 @@ struct guc_context_desc { u64 db_trigger_phy; u16 db_id; - struct guc_execlist_context lrc[I915_NUM_RINGS]; + struct guc_execlist_context lrc[GUC_MAX_ENGINES_NUM]; u8 attribute; @@ -344,7 +351,7 @@ struct guc_policy { } __packed; struct guc_policies { - struct guc_policy policy[GUC_CTX_PRIORITY_NUM][I915_NUM_RINGS]; + struct guc_policy policy[GUC_CTX_PRIORITY_NUM][GUC_MAX_ENGINES_NUM]; /* In micro seconds. How much time to allow before DPC processing is * called back via interrupt (to prevent DPC queue drain starving). @@ -388,14 +395,14 @@ struct guc_mmio_regset { struct guc_mmio_reg_state { struct guc_mmio_regset global_reg; - struct guc_mmio_regset engine_reg[I915_NUM_RINGS]; + struct guc_mmio_regset engine_reg[GUC_MAX_ENGINES_NUM]; /* MMIO registers that are set as non privileged */ struct __packed { u32 mmio_start; u32 offsets[GUC_MMIO_WHITE_LIST_MAX]; u32 count; - } mmio_white_list[I915_NUM_RINGS]; + } mmio_white_list[GUC_MAX_ENGINES_NUM]; } __packed; /* GuC Additional Data Struct */ @@ -406,7 +413,7 @@ struct guc_ads { u32 golden_context_lrca; u32 scheduler_policies; u32 reserved0[3]; - u32 eng_state_size[I915_NUM_RINGS]; + u32 eng_state_size[GUC_MAX_ENGINES_NUM]; u32 reserved2[4]; } __packed; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 116c10f..da97bc5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2088,6 +2088,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->name = "render ring"; ring->id = RCS; ring->exec_id = I915_EXEC_RENDER; + ring->guc_id = GUC_RENDER_ENGINE; ring->mmio_base = RENDER_RING_BASE; logical_ring_default_irqs(ring, GEN8_RCS_IRQ_SHIFT); @@ -2139,6 +2140,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->name = "bsd ring"; ring->id = VCS; ring->exec_id = I915_EXEC_BSD; + ring->guc_id = GUC_VIDEO_ENGINE; ring->mmio_base = GEN6_BSD_RING_BASE; logical_ring_default_irqs(ring, GEN8_VCS1_IRQ_SHIFT); @@ -2155,6 +2157,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->name = "bsd2 ring"; ring->id = VCS2; ring->exec_id = I915_EXEC_BSD; + ring->guc_id = GUC_VIDEO_ENGINE2; ring->mmio_base = GEN8_BSD2_RING_BASE; logical_ring_default_irqs(ring, GEN8_VCS2_IRQ_SHIFT); @@ -2171,6 +2174,7 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->name = "blitter ring"; ring->id = BCS; ring->exec_id = I915_EXEC_BLT; + ring->guc_id = GUC_BLITTER_ENGINE; ring->mmio_base = BLT_RING_BASE; logical_ring_default_irqs(ring, GEN8_BCS_IRQ_SHIFT); @@ -2187,6 +2191,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->name = "video enhancement ring"; ring->id = VECS; ring->exec_id = I915_EXEC_VEBOX; + ring->guc_id = GUC_VIDEOENHANCE_ENGINE; ring->mmio_base = VEBOX_RING_BASE; logical_ring_default_irqs(ring, GEN8_VECS_IRQ_SHIFT); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index b12f2aa..566b0ae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -158,6 +158,7 @@ struct intel_engine_cs { #define I915_NUM_RINGS 5 #define _VCS(n) (VCS + (n)) unsigned int exec_id; + unsigned int guc_id; u32 mmio_base; struct drm_device *dev; struct intel_ringbuffer *buffer; -- cgit v0.10.2 From 21fabbebff0e17c7698ed399cae23958c214cc82 Mon Sep 17 00:00:00 2001 From: Andreas Ziegler Date: Mon, 25 Jan 2016 12:41:19 +0100 Subject: drm/i915: Remove select to deleted STOP_MACHINE from Kconfig Commit 5bab6f60cb4d ("drm/i915: Serialise updates to GGTT with access through GGTT on Braswell") depended upon a working stop_machine() and so forced the selection of STOP_MACHINE. However, commit 86fffe4a61dd ("kernel: remove stop_machine() Kconfig dependency") removed the option STOP_MACHINE from init/Kconfig and ensured that stop_machine() universally works. Due to the order in which the patches were applied, removing the select from DRM_I915 got lost during merging. Remove the now obsolete select statement. Signed-off-by: Andreas Ziegler Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1453722079-2604-1-git-send-email-andreas.ziegler@fau.de Cc: drm-intel-fixes@lists.freedesktop.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index fcd77b2..051eab3 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -10,7 +10,6 @@ config DRM_I915 # the shmem_readpage() which depends upon tmpfs select SHMEM select TMPFS - select STOP_MACHINE select DRM_KMS_HELPER select DRM_PANEL select DRM_MIPI_DSI -- cgit v0.10.2 From 33136b06d54915680c36f4cd89dadef068b88974 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:47 +0000 Subject: drm/i915/gen9: Add framework to whitelist specific GPU registers Some of the HW registers are privileged and cannot be written to from non-privileged batch buffers coming from userspace unless they are added to the HW whitelist. This whitelist is maintained by HW and it is different from SW whitelist. Userspace need write access to them to implement preemption related WA. The reason for using this approach is, the register bits that control preemption granularity at the HW level are not context save/restored; so even if we set these bits always in kernel they are going to change once the context is switched out. We can consider making them non-privileged by default but these registers also contain other chicken bits which should not be allowed to be modified. In the later revisions controlling bits are save/restored at context level but in the existing revisions these are exported via other debug registers and should be on the whitelist. This patch adds changes to provide HW with a list of registers to be whitelisted. HW checks this list during execution and provides access accordingly. HW imposes a limit on the number of registers on whitelist and it is per-engine. At this point we are only enabling whitelist for RCS and we don't foresee any requirement for other engines. The registers to be whitelisted are added using generic workaround list mechanism, even these are only enablers for userspace workarounds. But by sharing this mechanism we get some test assets without additional cost (Mika). v2: rebase v3: parameterize RING_FORCE_TO_NONPRIV() as _MMIO() should be limited to i915_reg.h (Ville), drop inline for wa_ring_whitelist_reg (Mika). v4: improvements suggested by Chris Wilson. Clarify that this is HW whitelist and different from the one maintained in driver. This list is engine specific but it gets initialized along with other WA which is RCS specific thing, so make it clear that we are not doing any cross engine setup during initialization. Make HW whitelist count of each engine available in debugfs. Reviewed-by: Chris Wilson Reviewed-by: Mika Kuoppala Cc: Mika Kuoppala Cc: Chris Wilson Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-2-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index cea1844..863012a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3221,9 +3221,11 @@ static int i915_wa_registers(struct seq_file *m, void *unused) { int i; int ret; + struct intel_engine_cs *ring; struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_workarounds *workarounds = &dev_priv->workarounds; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -3231,15 +3233,18 @@ static int i915_wa_registers(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); - seq_printf(m, "Workarounds applied: %d\n", dev_priv->workarounds.count); - for (i = 0; i < dev_priv->workarounds.count; ++i) { + seq_printf(m, "Workarounds applied: %d\n", workarounds->count); + for_each_ring(ring, dev_priv, i) + seq_printf(m, "HW whitelist count for %s: %d\n", + ring->name, workarounds->hw_whitelist_count[i]); + for (i = 0; i < workarounds->count; ++i) { i915_reg_t addr; u32 mask, value, read; bool ok; - addr = dev_priv->workarounds.reg[i].addr; - mask = dev_priv->workarounds.reg[i].mask; - value = dev_priv->workarounds.reg[i].value; + addr = workarounds->reg[i].addr; + mask = workarounds->reg[i].mask; + value = workarounds->reg[i].value; read = I915_READ(addr); ok = (value & mask) == (read & mask); seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n", diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index afb0bee..211af53 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1657,11 +1657,18 @@ struct i915_wa_reg { u32 mask; }; -#define I915_MAX_WA_REGS 16 +/* + * RING_MAX_NONPRIV_SLOTS is per-engine but at this point we are only + * allowing it for RCS as we don't foresee any requirement of having + * a whitelist for other engines. When it is really required for + * other engines then the limit need to be increased. + */ +#define I915_MAX_WA_REGS (16 + RING_MAX_NONPRIV_SLOTS) struct i915_workarounds { struct i915_wa_reg reg[I915_MAX_WA_REGS]; u32 count; + u32 hw_whitelist_count[I915_NUM_RINGS]; }; struct i915_virtual_gpu { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0a98889..7938814 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1635,6 +1635,9 @@ enum skl_disp_power_wells { #define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ #define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ +#define RING_FORCE_TO_NONPRIV(base, i) _MMIO(((base)+0x4D0) + (i)*4) +#define RING_MAX_NONPRIV_SLOTS 12 + #define GEN7_TLB_RD_ADDR _MMIO(0x4700) #if 0 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9030e2b..43fa140 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -789,6 +789,22 @@ static int wa_add(struct drm_i915_private *dev_priv, #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val) +static int wa_ring_whitelist_reg(struct intel_engine_cs *ring, i915_reg_t reg) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_workarounds *wa = &dev_priv->workarounds; + const uint32_t index = wa->hw_whitelist_count[ring->id]; + + if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS)) + return -EINVAL; + + WA_WRITE(RING_FORCE_TO_NONPRIV(ring->mmio_base, index), + i915_mmio_reg_offset(reg)); + wa->hw_whitelist_count[ring->id]++; + + return 0; +} + static int gen8_init_workarounds(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; @@ -1117,6 +1133,7 @@ int init_workarounds_ring(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); dev_priv->workarounds.count = 0; + dev_priv->workarounds.hw_whitelist_count[RCS] = 0; if (IS_BROADWELL(dev)) return bdw_init_workarounds(ring); -- cgit v0.10.2 From e0f3fa096d6f319d1177b05d824fd8b36517368c Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:48 +0000 Subject: drm/i915/gen9: Add GEN8_CS_CHICKEN1 to HW whitelist Required for WaEnablePreemptionGranularityControlByUMD:skl,bxt This register is added to HW whitelist to support WA required for future enabling of pre-emptive command execution, WA implementation will be in userspace and it cannot program this register if it is not on HW whitelist. v2: explain purpose of WA (Chris) Reviewed-by: Nick Hoath Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-3-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7938814..511732e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5998,6 +5998,8 @@ enum skl_disp_power_wells { #define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) +#define GEN8_CS_CHICKEN1 _MMIO(0x2580) + /* GEN7 chicken */ #define GEN7_COMMON_SLICE_CHICKEN1 _MMIO(0x7010) # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 43fa140..c938b93 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -910,6 +910,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + int ret; /* WaEnableLbsSlaRetryTimerDecrement:skl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | @@ -980,6 +981,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* WaDisableSTUnitPowerOptimization:skl,bxt */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt */ + ret= wa_ring_whitelist_reg(ring, GEN8_CS_CHICKEN1); + if (ret) + return ret; + return 0; } -- cgit v0.10.2 From 3669ab6191b24ee800a5f78d3748b7d96df12115 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:49 +0000 Subject: drm/i915/gen9: Add HDC_CHICKEN1 to HW whitelist Required for WaAllowUMDToModifyHDCChicken1:skl,bxt This register is added to HW whitelist to support WA required for future enabling of pre-emptive command execution, WA implementation will be in userspace and it cannot program this register if it is not on HW whitelist. v2: explain purpose of changes (Chris) Reviewed-by: Nick Hoath Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-4-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 511732e..ed887cf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6045,6 +6045,8 @@ enum skl_disp_power_wells { #define HDC_FORCE_NON_COHERENT (1<<4) #define HDC_BARRIER_PERFORMANCE_DISABLE (1<<10) +#define GEN8_HDC_CHICKEN1 _MMIO(0x7304) + /* GEN9 chicken */ #define SLICE_ECO_CHICKEN0 _MMIO(0x7308) #define PIXEL_MASK_CAMMING_DISABLE (1 << 14) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c938b93..62f535c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -986,6 +986,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; + /* WaAllowUMDToModifyHDCChicken1:skl,bxt */ + ret = wa_ring_whitelist_reg(ring, GEN8_HDC_CHICKEN1); + if (ret) + return ret; + return 0; } -- cgit v0.10.2 From 2c8580e4e21c17011e78e7ac4e1fbab8b0d632bf Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:50 +0000 Subject: drm/i915/bxt: Add GEN9_CS_DEBUG_MODE1 to HW whitelist Required for, WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt WaDisableObjectLevelPreemptionForInstancedDraw:bxt WaDisableObjectLevelPreemtionForInstanceId:bxt According to WA database these are only applicable for BXT:A0 but since A0 and A1 shares the same GT these are extended for A1 as well. These are also required for SKL until B0 but not adding them because they are pre-production steppings. This register is added to HW whitelist to support WA required for future enabling of pre-emptive command execution, WA implementation will be in userspace and it cannot program this register if it is not on HW whitelist. v2: use lower case in register defines (Nick) v3: explain purpose of changes (Chris) Reviewed-by: Nick Hoath Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-5-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ed887cf..c51e7e9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5998,6 +5998,7 @@ enum skl_disp_power_wells { #define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) +#define GEN9_CS_DEBUG_MODE1 _MMIO(0x20ec) #define GEN8_CS_CHICKEN1 _MMIO(0x2580) /* GEN7 chicken */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 62f535c..a99f834 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1133,6 +1133,15 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } + /* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */ + /* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */ + /* WaDisableObjectLevelPreemtionForInstanceId:bxt */ + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { + ret = wa_ring_whitelist_reg(ring, GEN9_CS_DEBUG_MODE1); + if (ret) + return ret; + } + return 0; } -- cgit v0.10.2 From a786d53a2cf14f2c7abb6731f530aef1a8a1086a Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:51 +0000 Subject: drm/i915/bxt: Add GEN8_L3SQCREG4 to HW whitelist Required for WaDisableLSQCROPERFforOCL:bxt According to WA database these are only applicable for BXT:A0 but since A0 and A1 shares the same GT these are extended for A1 as well. This register is added to HW whitelist to support WA required for future enabling of pre-emptive command execution, WA implementation will be in userspace and it cannot program this register if it is not on HW whitelist. v2: explain purpose of changes (Chris) Reviewed-by: Nick Hoath Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-6-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a99f834..12eb1e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1136,10 +1136,15 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) /* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */ /* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */ /* WaDisableObjectLevelPreemtionForInstanceId:bxt */ + /* WaDisableLSQCROPERFforOCL:bxt */ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { ret = wa_ring_whitelist_reg(ring, GEN9_CS_DEBUG_MODE1); if (ret) return ret; + + ret = wa_ring_whitelist_reg(ring, GEN8_L3SQCREG4); + if (ret) + return ret; } return 0; -- cgit v0.10.2 From 6107497eee9f0f9de6f2aa8708db20842637d472 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:52 +0000 Subject: drm/i915/skl: Add GEN8_L3SQCREG4 to HW whitelist Required for WaDisableLSQCROPERFforOCL:skl This register is added to HW whitelist to support WA required for future enabling of pre-emptive command execution, WA implementation will be in userspace and it cannot program this register if it is not on HW whitelist. v2: explain purpose of changes (Chris) Reviewed-by: Nick Hoath Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-7-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 12eb1e0..262a7ea 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1098,6 +1098,11 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) GEN7_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + /* WaDisableLSQCROPERFforOCL:skl */ + ret = wa_ring_whitelist_reg(ring, GEN8_L3SQCREG4); + if (ret) + return ret; + return skl_tune_iz_hashing(ring); } -- cgit v0.10.2 From a78536e73f35471417df1de561d8e8b83da28734 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:53 +0000 Subject: drm/i915/skl: Enable Per context Preemption granularity control Per context preemption granularity control is only available from SKL:E0+ Actual WA is to disable percontext preemption granularity control until D0 which is the default case so this is equivalent to the inverse of WaDisablePerCtxtPreemptionGranularityControl:skl v2: add some detail to commit msg (Chris) Reviewed-by: Nick Hoath Cc: Dave Gordon Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-8-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c51e7e9..65e32a3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5995,6 +5995,9 @@ enum skl_disp_power_wells { #define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23) #define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23) +#define GEN7_FF_SLICE_CS_CHICKEN1 _MMIO(0x20e0) +#define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1<<14) + #define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 262a7ea..d07c6a9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1046,6 +1046,16 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; + /* + * Actual WA is to disable percontext preemption granularity control + * until D0 which is the default case so this is equivalent to + * !WaDisablePerCtxtPreemptionGranularityControl:skl + */ + if (IS_SKL_REVID(dev, SKL_REVID_E0, REVID_FOREVER)) { + I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, + _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); + } + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) { /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ I915_WRITE(FF_SLICE_CS_CHICKEN2, -- cgit v0.10.2 From 6ecf56ae1d20d00a010a7d6d453031e413c674b8 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 21 Jan 2016 21:43:54 +0000 Subject: drm/i915/gen9: Add WaOCLCoherentLineFlush This is mainly required for future enabling of pre-emptive command execution. v2: explain purpose of change (Chris) Reviewed-by: Nick Hoath Cc: Dave Gordon Signed-off-by: Arun Siluvery Link: http://patchwork.freedesktop.org/patch/msgid/1453412634-29238-9-git-send-email-arun.siluvery@linux.intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d07c6a9..6f5b511 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -981,6 +981,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* WaDisableSTUnitPowerOptimization:skl,bxt */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); + /* WaOCLCoherentLineFlush:skl,bxt */ + I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) | + GEN8_LQSC_FLUSH_COHERENT_LINES)); + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt */ ret= wa_ring_whitelist_reg(ring, GEN8_CS_CHICKEN1); if (ret) -- cgit v0.10.2 From 768e159f433c97f5221a3662217de5a1cb3b9b95 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 21 Jan 2016 17:32:43 +0000 Subject: drm/i915: Improve handling of overlapping objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic interval tree we use to speed up range invalidation is an augmented rbtree that can report all overlapping intervals for a given range. Therefore we do not need to degrade to a linear list if we find overlapping objects. Oops. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Michał Winiarski Link: http://patchwork.freedesktop.org/patch/msgid/1453397563-2848-1-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Michał Winiarski Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 19fb0bdd..74a4d17 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -49,21 +49,18 @@ struct i915_mmu_notifier { struct hlist_node node; struct mmu_notifier mn; struct rb_root objects; - struct list_head linear; - bool has_linear; }; struct i915_mmu_object { struct i915_mmu_notifier *mn; + struct drm_i915_gem_object *obj; struct interval_tree_node it; struct list_head link; - struct drm_i915_gem_object *obj; struct work_struct work; - bool active; - bool is_linear; + bool attached; }; -static void __cancel_userptr__worker(struct work_struct *work) +static void cancel_userptr(struct work_struct *work) { struct i915_mmu_object *mo = container_of(work, typeof(*mo), work); struct drm_i915_gem_object *obj = mo->obj; @@ -94,24 +91,22 @@ static void __cancel_userptr__worker(struct work_struct *work) mutex_unlock(&dev->struct_mutex); } -static unsigned long cancel_userptr(struct i915_mmu_object *mo) +static void add_object(struct i915_mmu_object *mo) { - unsigned long end = mo->obj->userptr.ptr + mo->obj->base.size; - - /* The mmu_object is released late when destroying the - * GEM object so it is entirely possible to gain a - * reference on an object in the process of being freed - * since our serialisation is via the spinlock and not - * the struct_mutex - and consequently use it after it - * is freed and then double free it. - */ - if (mo->active && kref_get_unless_zero(&mo->obj->base.refcount)) { - schedule_work(&mo->work); - /* only schedule one work packet to avoid the refleak */ - mo->active = false; - } + if (mo->attached) + return; + + interval_tree_insert(&mo->it, &mo->mn->objects); + mo->attached = true; +} - return end; +static void del_object(struct i915_mmu_object *mo) +{ + if (!mo->attached) + return; + + interval_tree_remove(&mo->it, &mo->mn->objects); + mo->attached = false; } static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, @@ -122,28 +117,36 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn); struct i915_mmu_object *mo; + struct interval_tree_node *it; + LIST_HEAD(cancelled); + + if (RB_EMPTY_ROOT(&mn->objects)) + return; /* interval ranges are inclusive, but invalidate range is exclusive */ end--; spin_lock(&mn->lock); - if (mn->has_linear) { - list_for_each_entry(mo, &mn->linear, link) { - if (mo->it.last < start || mo->it.start > end) - continue; - - cancel_userptr(mo); - } - } else { - struct interval_tree_node *it; + it = interval_tree_iter_first(&mn->objects, start, end); + while (it) { + /* The mmu_object is released late when destroying the + * GEM object so it is entirely possible to gain a + * reference on an object in the process of being freed + * since our serialisation is via the spinlock and not + * the struct_mutex - and consequently use it after it + * is freed and then double free it. To prevent that + * use-after-free we only acquire a reference on the + * object if it is not in the process of being destroyed. + */ + mo = container_of(it, struct i915_mmu_object, it); + if (kref_get_unless_zero(&mo->obj->base.refcount)) + schedule_work(&mo->work); - it = interval_tree_iter_first(&mn->objects, start, end); - while (it) { - mo = container_of(it, struct i915_mmu_object, it); - start = cancel_userptr(mo); - it = interval_tree_iter_next(it, start, end); - } + list_add(&mo->link, &cancelled); + it = interval_tree_iter_next(it, start, end); } + list_for_each_entry(mo, &cancelled, link) + del_object(mo); spin_unlock(&mn->lock); } @@ -164,8 +167,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) spin_lock_init(&mn->lock); mn->mn.ops = &i915_gem_userptr_notifier; mn->objects = RB_ROOT; - INIT_LIST_HEAD(&mn->linear); - mn->has_linear = false; /* Protected by mmap_sem (write-lock) */ ret = __mmu_notifier_register(&mn->mn, mm); @@ -177,85 +178,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) return mn; } -static int -i915_mmu_notifier_add(struct drm_device *dev, - struct i915_mmu_notifier *mn, - struct i915_mmu_object *mo) -{ - struct interval_tree_node *it; - int ret = 0; - - /* By this point we have already done a lot of expensive setup that - * we do not want to repeat just because the caller (e.g. X) has a - * signal pending (and partly because of that expensive setup, X - * using an interrupt timer is likely to get stuck in an EINTR loop). - */ - mutex_lock(&dev->struct_mutex); - - /* Make sure we drop the final active reference (and thereby - * remove the objects from the interval tree) before we do - * the check for overlapping objects. - */ - i915_gem_retire_requests(dev); - - spin_lock(&mn->lock); - it = interval_tree_iter_first(&mn->objects, - mo->it.start, mo->it.last); - if (it) { - struct drm_i915_gem_object *obj; - - /* We only need to check the first object in the range as it - * either has cancelled gup work queued and we need to - * return back to the user to give time for the gup-workers - * to flush their object references upon which the object will - * be removed from the interval-tree, or the the range is - * still in use by another client and the overlap is invalid. - * - * If we do have an overlap, we cannot use the interval tree - * for fast range invalidation. - */ - - obj = container_of(it, struct i915_mmu_object, it)->obj; - if (!obj->userptr.workers) - mn->has_linear = mo->is_linear = true; - else - ret = -EAGAIN; - } else - interval_tree_insert(&mo->it, &mn->objects); - - if (ret == 0) - list_add(&mo->link, &mn->linear); - - spin_unlock(&mn->lock); - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -static bool i915_mmu_notifier_has_linear(struct i915_mmu_notifier *mn) -{ - struct i915_mmu_object *mo; - - list_for_each_entry(mo, &mn->linear, link) - if (mo->is_linear) - return true; - - return false; -} - -static void -i915_mmu_notifier_del(struct i915_mmu_notifier *mn, - struct i915_mmu_object *mo) -{ - spin_lock(&mn->lock); - list_del(&mo->link); - if (mo->is_linear) - mn->has_linear = i915_mmu_notifier_has_linear(mn); - else - interval_tree_remove(&mo->it, &mn->objects); - spin_unlock(&mn->lock); -} - static void i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) { @@ -265,7 +187,9 @@ i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) if (mo == NULL) return; - i915_mmu_notifier_del(mo->mn, mo); + spin_lock(&mo->mn->lock); + del_object(mo); + spin_unlock(&mo->mn->lock); kfree(mo); obj->userptr.mmu_object = NULL; @@ -299,7 +223,6 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, { struct i915_mmu_notifier *mn; struct i915_mmu_object *mo; - int ret; if (flags & I915_USERPTR_UNSYNCHRONIZED) return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; @@ -316,16 +239,10 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, return -ENOMEM; mo->mn = mn; - mo->it.start = obj->userptr.ptr; - mo->it.last = mo->it.start + obj->base.size - 1; mo->obj = obj; - INIT_WORK(&mo->work, __cancel_userptr__worker); - - ret = i915_mmu_notifier_add(obj->base.dev, mn, mo); - if (ret) { - kfree(mo); - return ret; - } + mo->it.start = obj->userptr.ptr; + mo->it.last = obj->userptr.ptr + obj->base.size - 1; + INIT_WORK(&mo->work, cancel_userptr); obj->userptr.mmu_object = mo; return 0; @@ -552,8 +469,10 @@ __i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, /* In order to serialise get_pages with an outstanding * cancel_userptr, we must drop the struct_mutex and try again. */ - if (!value || !work_pending(&obj->userptr.mmu_object->work)) - obj->userptr.mmu_object->active = value; + if (!value) + del_object(obj->userptr.mmu_object); + else if (!work_pending(&obj->userptr.mmu_object->work)) + add_object(obj->userptr.mmu_object); else ret = -EAGAIN; spin_unlock(&obj->userptr.mmu_object->mn->lock); -- cgit v0.10.2 From 1803c035efb88afb9d3e7feb279ac29a83216382 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 21 Jan 2016 19:37:45 +0000 Subject: drm/i915: Fix context/engine cleanup order Swap the order of context & engine cleanup, so that contexts are cleaned up first, and *then* engines. This is a more sensible order anyway, but in particular has become necessary since the 'intel_ring_initialized() must be simple and inline' patch, which now uses ring->dev as an 'initialised' flag, so it can now be NULL after engine teardown. This in turn can cause a problem in the context code, which (used to) check the ring->dev->struct_mutex -- causing a fault if ring->dev was NULL. Also rename the cleanup function to reflect what it actually does (cleanup engines, not a ringbuffer), and fix an annoying whitespace issue. v2: Also make the fix in i915_load_modeset_init, not just in i915_driver_unload (Chris Wilson) v3: Had extra stuff in it. v4: Reverted extra stuff (so we're back to v2). Rebased and updated commentary above (Dave Gordon). Signed-off-by: Nick Hoath Signed-off-by: Dave Gordon Reviewed-by: Chris Wilson (v2) Cc: Mika Kuoppala Cc: Daniel Vetter Cc: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1453405067-32890-3-git-send-email-david.s.gordon@intel.com Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index d70d96f..4725e8d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -451,8 +451,8 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: mutex_lock(&dev->struct_mutex); - i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); + i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); cleanup_irq: intel_guc_ucode_fini(dev); @@ -1196,8 +1196,8 @@ int i915_driver_unload(struct drm_device *dev) intel_guc_ucode_fini(dev); mutex_lock(&dev->struct_mutex); - i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); + i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 211af53..01cc982 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3019,7 +3019,7 @@ int i915_gem_init_rings(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice); void i915_gem_init_swizzling(struct drm_device *dev); -void i915_gem_cleanup_ringbuffer(struct drm_device *dev); +void i915_gem_cleanup_engines(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct drm_i915_gem_request *req, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 371bbb2..799a53a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4912,7 +4912,7 @@ i915_gem_init_hw(struct drm_device *dev) req = i915_gem_request_alloc(ring, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -4925,7 +4925,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -4933,7 +4933,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -5008,7 +5008,7 @@ out_unlock: } void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) +i915_gem_cleanup_engines(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; @@ -5017,13 +5017,14 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) for_each_ring(ring, dev_priv, i) dev_priv->gt.cleanup_ring(ring); - if (i915.enable_execlists) - /* - * Neither the BIOS, ourselves or any other kernel - * expects the system to be in execlists mode on startup, - * so we need to reset the GPU back to legacy mode. - */ - intel_gpu_reset(dev); + if (i915.enable_execlists) { + /* + * Neither the BIOS, ourselves or any other kernel + * expects the system to be in execlists mode on startup, + * so we need to reset the GPU back to legacy mode. + */ + intel_gpu_reset(dev); + } } static void -- cgit v0.10.2 From 9a15a87338d9f28593172ec7ec2c628f3ae494b9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Jan 2016 13:40:29 +0100 Subject: Revert "drm/i915: Fix context/engine cleanup order" This reverts commit 1803c035efb88afb9d3e7feb279ac29a83216382. It seems to blow up on module unload due to a use-after free hitting a BUG_ON with CONFIG_DEBUG_SG. Quoting from Tvrtko's mail: "I've decoded the instructions and it pointed to SG_MAGIC checking: 488b8098010000 mov 0x198(%rax),%rax ba21436587 mov $0x87654321,%edx 488b00 mov (%rax),%rax *** CRASH "Grep showed 0x87654321 is SG_MAGIC, so likely candidate for this code pattern is: static inline struct page *sg_page(struct scatterlist *sg) { BUG_ON(sg->sg_magic != SG_MAGIC); BUG_ON(sg_is_chain(sg)); return (struct page *)((sg)->page_link & ~0x3); } "Which would mean the offender is in intel_logical_ring_cleanup is most likely: ... if (ring->status_page.obj) { kunmap(sg_page(ring->status_page.obj->pages->sgl)); ring->status_page.obj = NULL; } ... "I think that the i915_gem_context_fini will do a final unref on dev_priv->kernel_context and then the ring buff has a copy which is left dangling because: lrc_setup_hardware_status_page(ring, dev_priv->kernel_context->engine[ring->id].state); and: ring->status_page.obj = default_ctx_obj; "Where default_ctx_obj == dev_priv->kernel_context->engine[ring->id].state So indeed looks like the unload ordering is the trigger. In fact it is almost the same fragility wrt/ kernel_context hidden dependency I expressed my worry about in an e-mail yesterday or so. It only shows if CONFIG_DEBUG_SG is set, otherwise it accesses freed memory and probably just survives." This causes serious trouble in our CI system since it took out all gen8+ machines. Not yet clear why this wasn't caught in pre-merge testing. Backtrace from CI, for posterity: [ 163.737836] general protection fault: 0000 [#1] PREEMPT SMP [ 163.737849] Modules linked in: ax88179_178a usbnet mii snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic i915(-) x86_pkg_temp_thermal intel_powerclamp coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm mei_me mei i2c_hid e1000e ptp pps_core [last unloaded: snd_hda_intel] [ 163.737902] CPU: 0 PID: 5812 Comm: rmmod Tainted: G U W 4.5.0-rc1-gfxbench+ #1 [ 163.737911] Hardware name: System manufacturer System Product Name/Z170M-PLUS, BIOS 0505 11/16/2015 [ 163.737920] task: ffff8800bb99cf80 ti: ffff88022ff2c000 task.ti: ffff88022ff2c000 [ 163.737928] RIP: 0010:[] [] intel_logical_ring_cleanup+0x83/0x100 [i915] [ 163.737969] RSP: 0018:ffff88022ff2fd30 EFLAGS: 00010282 [ 163.737975] RAX: 6b6b6b6b6b6b6b6b RBX: ffff8800bb2f31b8 RCX: 0000000000000002 [ 163.737982] RDX: 0000000087654321 RSI: 000000000000000d RDI: ffff8800bb2f31f0 [ 163.737989] RBP: ffff88022ff2fd40 R08: 0000000000000000 R09: 0000000000000001 [ 163.737996] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800bb2f0000 [ 163.738003] R13: ffff8800bb2f8fc8 R14: ffff8800bb285668 R15: 000055af1ae55210 [ 163.738010] FS: 00007f187014b700(0000) GS:ffff88023bc00000(0000) knlGS:0000000000000000 [ 163.738021] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 163.738030] CR2: 0000558f84e4cbc8 CR3: 000000022cd55000 CR4: 00000000003406f0 [ 163.738039] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 163.738048] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 163.738057] Stack: [ 163.738062] ffff8800bb2f31b8 ffff8800bb2f0000 ffff88022ff2fd70 ffffffffa0180414 [ 163.738079] ffff8800bb2f0000 ffff8800bb285668 ffff8800bb2856c8 ffffffffa0242460 [ 163.738094] ffff88022ff2fd98 ffffffffa0202d30 ffff8800bb285668 ffff8800bb285668 [ 163.738109] Call Trace: [ 163.738140] [] i915_gem_cleanup_engines+0x34/0x60 [i915] [ 163.738185] [] i915_driver_unload+0x150/0x270 [i915] [ 163.738198] [] drm_dev_unregister+0x24/0xa0 [ 163.738208] [] drm_put_dev+0x1e/0x60 [ 163.738225] [] i915_pci_remove+0x10/0x20 [i915] [ 163.738237] [] pci_device_remove+0x34/0xb0 [ 163.738249] [] __device_release_driver+0x95/0x140 [ 163.738259] [] driver_detach+0xb6/0xc0 [ 163.738268] [] bus_remove_driver+0x53/0xd0 [ 163.738278] [] driver_unregister+0x27/0x50 [ 163.738289] [] pci_unregister_driver+0x25/0x70 [ 163.738299] [] drm_pci_exit+0x74/0x90 [ 163.738337] [] i915_exit+0x20/0x1a5 [i915] [ 163.738349] [] SyS_delete_module+0x18f/0x1f0 [ 163.738361] [] entry_SYSCALL_64_fastpath+0x16/0x73 [ 163.738370] Code: ff d0 48 89 df e8 de a1 fd ff 48 8d 7b 38 e8 25 ab fd ff 48 8b 83 90 00 00 00 48 85 c0 74 25 48 8b 80 98 01 00 00 ba 21 43 65 87 <48> 8b 00 48 39 10 75 3c f6 40 08 01 75 38 48 c7 83 90 00 00 00 [ 163.738459] RIP [] intel_logical_ring_cleanup+0x83/0x100 [i915] [ 163.738498] RSP [ 163.738507] ---[ end trace 68f69ce4740fa44f ]--- Cc: Nick Hoath Cc: Dave Gordon Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Tested-by: Mika Kuoppala Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4725e8d..d70d96f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -451,8 +451,8 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); - i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); cleanup_irq: intel_guc_ucode_fini(dev); @@ -1196,8 +1196,8 @@ int i915_driver_unload(struct drm_device *dev) intel_guc_ucode_fini(dev); mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); - i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 01cc982..211af53 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3019,7 +3019,7 @@ int i915_gem_init_rings(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice); void i915_gem_init_swizzling(struct drm_device *dev); -void i915_gem_cleanup_engines(struct drm_device *dev); +void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct drm_i915_gem_request *req, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 799a53a..371bbb2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4912,7 +4912,7 @@ i915_gem_init_hw(struct drm_device *dev) req = i915_gem_request_alloc(ring, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); - i915_gem_cleanup_engines(dev); + i915_gem_cleanup_ringbuffer(dev); goto out; } @@ -4925,7 +4925,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_engines(dev); + i915_gem_cleanup_ringbuffer(dev); goto out; } @@ -4933,7 +4933,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_engines(dev); + i915_gem_cleanup_ringbuffer(dev); goto out; } @@ -5008,7 +5008,7 @@ out_unlock: } void -i915_gem_cleanup_engines(struct drm_device *dev) +i915_gem_cleanup_ringbuffer(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; @@ -5017,14 +5017,13 @@ i915_gem_cleanup_engines(struct drm_device *dev) for_each_ring(ring, dev_priv, i) dev_priv->gt.cleanup_ring(ring); - if (i915.enable_execlists) { - /* - * Neither the BIOS, ourselves or any other kernel - * expects the system to be in execlists mode on startup, - * so we need to reset the GPU back to legacy mode. - */ - intel_gpu_reset(dev); - } + if (i915.enable_execlists) + /* + * Neither the BIOS, ourselves or any other kernel + * expects the system to be in execlists mode on startup, + * so we need to reset the GPU back to legacy mode. + */ + intel_gpu_reset(dev); } static void -- cgit v0.10.2 From 89250fec1c2b7846cd994e91d8dd7398e67ae129 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:26 +0200 Subject: drm/i915: Sanitize DMC/CSR ucode cleanup code commit ebae38d061df3deffa7c17b030ea14a5216ee55f Author: Animesh Manna Date: Wed Oct 28 23:58:55 2015 +0200 drm/i915/gen9: csr_init after runtime pm enable moved the DMC/CSR initialization later during driver loading, but didn't move the cleanup earlier correspondingly during unloading. Fix this up. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-2-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index d70d96f..4b2c073 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -404,7 +404,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = intel_irq_install(dev_priv); if (ret) - goto cleanup_gem_stolen; + goto cleanup_csr; intel_setup_gmbus(dev); @@ -458,7 +458,8 @@ cleanup_irq: intel_guc_ucode_fini(dev); drm_irq_uninstall(dev); intel_teardown_gmbus(dev); -cleanup_gem_stolen: +cleanup_csr: + intel_csr_ucode_fini(dev_priv); i915_gem_cleanup_stolen(dev); cleanup_vga_switcheroo: vga_switcheroo_unregister_client(dev->pdev); @@ -945,7 +946,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ret = i915_gem_gtt_init(dev); if (ret) - goto out_freecsr; + goto out_uncore_fini; /* WARNING: Apparently we must kick fbdev drivers before vgacon, * otherwise the vga fbdev driver falls over. */ @@ -1115,8 +1116,7 @@ out_mtrrfree: io_mapping_free(dev_priv->gtt.mappable); out_gtt: i915_global_gtt_cleanup(dev); -out_freecsr: - intel_csr_ucode_fini(dev_priv); +out_uncore_fini: intel_uncore_fini(dev); pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: @@ -1182,6 +1182,8 @@ int i915_driver_unload(struct drm_device *dev) vga_switcheroo_unregister_client(dev->pdev); vga_client_register(dev->pdev, NULL, NULL, NULL); + intel_csr_ucode_fini(dev_priv); + /* Free error state after interrupts are fully disabled. */ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work); i915_destroy_error_state(dev); @@ -1202,8 +1204,6 @@ int i915_driver_unload(struct drm_device *dev) intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); - intel_csr_ucode_fini(dev_priv); - intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->hotplug.dp_wq); -- cgit v0.10.2 From 02036cee8373712d154a7cac76e1325f93fce9e5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:27 +0200 Subject: drm/i915: Sanitize i915_get_bridge_dev() error path Clarify the name of the label on the error path, making it clear what's being cleaned up. The kmem_cache_destroy() calls are NOPs on the corresponding error path. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-3-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4b2c073..5caea9e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -916,7 +916,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (i915_get_bridge_dev(dev)) { ret = -EIO; - goto free_priv; + goto out_runtime_pm_put; } mmio_bar = IS_GEN2(dev) ? 1 : 0; @@ -1121,11 +1121,10 @@ out_uncore_fini: pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: pci_dev_put(dev_priv->bridge_dev); -free_priv: kmem_cache_destroy(dev_priv->requests); kmem_cache_destroy(dev_priv->vmas); kmem_cache_destroy(dev_priv->objects); - +out_runtime_pm_put: intel_runtime_pm_put(dev_priv); kfree(dev_priv); -- cgit v0.10.2 From a8a40589257a280b49c7d9b744910036d11aac5d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:28 +0200 Subject: drm/i915: Sanitize GEM shrinker init and clean-up Factor out the common GEM shrinker clean-up code and call the shrinker init function from the same function from where the corresponding shrinker clean-up function is called. Also add sanity checking to the shrinker and OOM registration calls. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-4-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 5caea9e..adc5fe7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1035,6 +1035,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_opregion_setup(dev); i915_gem_load(dev); + i915_gem_shrinker_init(dev_priv); /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there @@ -1098,8 +1099,7 @@ out_power_well: intel_power_domains_fini(dev_priv); drm_vblank_cleanup(dev); out_gem_unload: - WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier)); - unregister_shrinker(&dev_priv->mm.shrinker); + i915_gem_shrinker_cleanup(dev_priv); if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); @@ -1152,8 +1152,7 @@ int i915_driver_unload(struct drm_device *dev) i915_teardown_sysfs(dev); - WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier)); - unregister_shrinker(&dev_priv->mm.shrinker); + i915_gem_shrinker_cleanup(dev_priv); io_mapping_free(dev_priv->gtt.mappable); arch_phys_wc_del(dev_priv->gtt.mtrr); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 211af53..abfb8c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3261,6 +3261,7 @@ unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, #define I915_SHRINK_ACTIVE 0x8 unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); void i915_gem_shrinker_init(struct drm_i915_private *dev_priv); +void i915_gem_shrinker_cleanup(struct drm_i915_private *dev_priv); /* i915_gem_tiling.c */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 371bbb2..7ce76c2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5100,8 +5100,6 @@ i915_gem_load(struct drm_device *dev) dev_priv->mm.interruptible = true; - i915_gem_shrinker_init(dev_priv); - mutex_init(&dev_priv->fb_tracking.lock); } diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 16da9c1..58c1e59 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -367,8 +367,20 @@ void i915_gem_shrinker_init(struct drm_i915_private *dev_priv) dev_priv->mm.shrinker.scan_objects = i915_gem_shrinker_scan; dev_priv->mm.shrinker.count_objects = i915_gem_shrinker_count; dev_priv->mm.shrinker.seeks = DEFAULT_SEEKS; - register_shrinker(&dev_priv->mm.shrinker); + WARN_ON(register_shrinker(&dev_priv->mm.shrinker)); dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom; - register_oom_notifier(&dev_priv->mm.oom_notifier); + WARN_ON(register_oom_notifier(&dev_priv->mm.oom_notifier)); +} + +/** + * i915_gem_shrinker_cleanup - Clean up i915 shrinker + * @dev_priv: i915 device + * + * This function unregisters the i915 shrinker and OOM handler. + */ +void i915_gem_shrinker_cleanup(struct drm_i915_private *dev_priv) +{ + WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier)); + unregister_shrinker(&dev_priv->mm.shrinker); } -- cgit v0.10.2 From d64aa096a4fb0f438563ad8126123766c2190aa8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:29 +0200 Subject: drm/i915: Sanitize i915_gem_load() init and clean-up Factor out common clean-up code for the GEM load time init function. Also rename i915_gem_load() to i915_gem_load_init() to have a better match with its new clean-up function. No functional change. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-5-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index adc5fe7..348366c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1034,7 +1034,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_setup_mchbar(dev); intel_opregion_setup(dev); - i915_gem_load(dev); + i915_gem_load_init(dev); i915_gem_shrinker_init(dev_priv); /* On the 945G/GM, the chipset reports the MSI capability on the @@ -1121,9 +1121,7 @@ out_uncore_fini: pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: pci_dev_put(dev_priv->bridge_dev); - kmem_cache_destroy(dev_priv->requests); - kmem_cache_destroy(dev_priv->vmas); - kmem_cache_destroy(dev_priv->objects); + i915_gem_load_cleanup(dev); out_runtime_pm_put: intel_runtime_pm_put(dev_priv); @@ -1215,9 +1213,7 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->regs != NULL) pci_iounmap(dev->pdev, dev_priv->regs); - kmem_cache_destroy(dev_priv->requests); - kmem_cache_destroy(dev_priv->vmas); - kmem_cache_destroy(dev_priv->objects); + i915_gem_load_cleanup(dev); pci_dev_put(dev_priv->bridge_dev); kfree(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index abfb8c9..905e90f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2848,7 +2848,8 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -void i915_gem_load(struct drm_device *dev); +void i915_gem_load_init(struct drm_device *dev); +void i915_gem_load_cleanup(struct drm_device *dev); void *i915_gem_object_alloc(struct drm_device *dev); void i915_gem_object_free(struct drm_i915_gem_object *obj); void i915_gem_object_init(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7ce76c2..c1bb6a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5034,7 +5034,7 @@ init_ring_lists(struct intel_engine_cs *ring) } void -i915_gem_load(struct drm_device *dev) +i915_gem_load_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int i; @@ -5103,6 +5103,15 @@ i915_gem_load(struct drm_device *dev) mutex_init(&dev_priv->fb_tracking.lock); } +void i915_gem_load_cleanup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + + kmem_cache_destroy(dev_priv->requests); + kmem_cache_destroy(dev_priv->vmas); + kmem_cache_destroy(dev_priv->objects); +} + void i915_gem_release(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; -- cgit v0.10.2 From 399bb5b6db027b1834d10496909d60214779126c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:30 +0200 Subject: drm/i915: Move allocation of various workqueues earlier during init Workqueue initalization doesn't depend on any other device specific resource, so move it close to the beginning, so we don't need to consider them when thinking about dependencies for other resources. Also factor out things to separate init/cleanup functions to make i915_driver_load()/unload() clearer, atm it's somewhat difficult to follow there in what order resources are inited/cleaned-up. Suggested-by: Chris Wilson Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-6-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 348366c..1446e639 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -856,6 +856,54 @@ static void intel_init_dpio(struct drm_i915_private *dev_priv) } } +static int i915_workqueues_init(struct drm_i915_private *dev_priv) +{ + /* + * The i915 workqueue is primarily used for batched retirement of + * requests (and thus managing bo) once the task has been completed + * by the GPU. i915_gem_retire_requests() is called directly when we + * need high-priority retirement, such as waiting for an explicit + * bo. + * + * It is also used for periodic low-priority events, such as + * idle-timers and recording error state. + * + * All tasks on the workqueue are expected to acquire the dev mutex + * so there is no point in running more than one instance of the + * workqueue at any time. Use an ordered one. + */ + dev_priv->wq = alloc_ordered_workqueue("i915", 0); + if (dev_priv->wq == NULL) + goto out_err; + + dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); + if (dev_priv->hotplug.dp_wq == NULL) + goto out_free_wq; + + dev_priv->gpu_error.hangcheck_wq = + alloc_ordered_workqueue("i915-hangcheck", 0); + if (dev_priv->gpu_error.hangcheck_wq == NULL) + goto out_free_dp_wq; + + return 0; + +out_free_dp_wq: + destroy_workqueue(dev_priv->hotplug.dp_wq); +out_free_wq: + destroy_workqueue(dev_priv->wq); +out_err: + DRM_ERROR("Failed to allocate workqueues.\n"); + + return -ENOMEM; +} + +static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv) +{ + destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); + destroy_workqueue(dev_priv->hotplug.dp_wq); + destroy_workqueue(dev_priv->wq); +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -898,6 +946,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) mutex_init(&dev_priv->modeset_restore_lock); mutex_init(&dev_priv->av_mutex); + ret = i915_workqueues_init(dev_priv); + if (ret < 0) + goto out_free_priv; + intel_pm_setup(dev); intel_runtime_pm_get(dev_priv); @@ -992,41 +1044,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, aperture_size); - /* The i915 workqueue is primarily used for batched retirement of - * requests (and thus managing bo) once the task has been completed - * by the GPU. i915_gem_retire_requests() is called directly when we - * need high-priority retirement, such as waiting for an explicit - * bo. - * - * It is also used for periodic low-priority events, such as - * idle-timers and recording error state. - * - * All tasks on the workqueue are expected to acquire the dev mutex - * so there is no point in running more than one instance of the - * workqueue at any time. Use an ordered one. - */ - dev_priv->wq = alloc_ordered_workqueue("i915", 0); - if (dev_priv->wq == NULL) { - DRM_ERROR("Failed to create our workqueue.\n"); - ret = -ENOMEM; - goto out_mtrrfree; - } - - dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); - if (dev_priv->hotplug.dp_wq == NULL) { - DRM_ERROR("Failed to create our dp workqueue.\n"); - ret = -ENOMEM; - goto out_freewq; - } - - dev_priv->gpu_error.hangcheck_wq = - alloc_ordered_workqueue("i915-hangcheck", 0); - if (dev_priv->gpu_error.hangcheck_wq == NULL) { - DRM_ERROR("Failed to create our hangcheck workqueue.\n"); - ret = -ENOMEM; - goto out_freedpwq; - } - intel_irq_init(dev_priv); intel_uncore_sanitize(dev); @@ -1106,12 +1123,6 @@ out_gem_unload: intel_teardown_mchbar(dev); pm_qos_remove_request(&dev_priv->pm_qos); - destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); -out_freedpwq: - destroy_workqueue(dev_priv->hotplug.dp_wq); -out_freewq: - destroy_workqueue(dev_priv->wq); -out_mtrrfree: arch_phys_wc_del(dev_priv->gtt.mtrr); io_mapping_free(dev_priv->gtt.mappable); out_gtt: @@ -1124,8 +1135,10 @@ put_bridge: i915_gem_load_cleanup(dev); out_runtime_pm_put: intel_runtime_pm_put(dev_priv); - + i915_workqueues_cleanup(dev_priv); +out_free_priv: kfree(dev_priv); + return ret; } @@ -1202,9 +1215,6 @@ int i915_driver_unload(struct drm_device *dev) intel_teardown_mchbar(dev); - destroy_workqueue(dev_priv->hotplug.dp_wq); - destroy_workqueue(dev_priv->wq); - destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); pm_qos_remove_request(&dev_priv->pm_qos); i915_global_gtt_cleanup(dev); @@ -1215,6 +1225,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_load_cleanup(dev); pci_dev_put(dev_priv->bridge_dev); + i915_workqueues_cleanup(dev_priv); kfree(dev_priv); return 0; -- cgit v0.10.2 From ad5c3d3ffbb26094b0b76751aef4ee4e4854996c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:31 +0200 Subject: drm/i915: Move MCHBAR setup earlier during init Move the MCHBAR setup right after the MMIO setup, since the two things are logically related and the MCHBAR setup code doesn't depend on any other device specific resource. We'll also need MCHBAR to be ready earlier in an upcoming patch, so this is also a preparation for that. Factor out the init/clean-up code to separate functions to make things clearer in the i915_driver_load()/unload() functions. Suggested-by: Chris Wilson Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-7-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1446e639..697807d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -904,6 +904,46 @@ static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv) destroy_workqueue(dev_priv->wq); } +static int i915_mmio_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + int mmio_bar; + int mmio_size; + + mmio_bar = IS_GEN2(dev) ? 1 : 0; + /* + * Before gen4, the registers and the GTT are behind different BARs. + * However, from gen4 onwards, the registers and the GTT are shared + * in the same BAR, so we want to restrict this ioremap from + * clobbering the GTT which we want ioremap_wc instead. Fortunately, + * the register BAR remains the same size for all the earlier + * generations up to Ironlake. + */ + if (INTEL_INFO(dev)->gen < 5) + mmio_size = 512 * 1024; + else + mmio_size = 2 * 1024 * 1024; + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); + if (dev_priv->regs == NULL) { + DRM_ERROR("failed to map registers\n"); + + return -EIO; + } + + /* Try to make sure MCHBAR is enabled before poking at it */ + intel_setup_mchbar(dev); + + return 0; +} + +static void i915_mmio_cleanup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + + intel_teardown_mchbar(dev); + pci_iounmap(dev->pdev, dev_priv->regs); +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -919,7 +959,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; struct intel_device_info *info, *device_info; - int ret = 0, mmio_bar, mmio_size; + int ret = 0; uint32_t aperture_size; info = (struct intel_device_info *) flags; @@ -971,25 +1011,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_runtime_pm_put; } - mmio_bar = IS_GEN2(dev) ? 1 : 0; - /* Before gen4, the registers and the GTT are behind different BARs. - * However, from gen4 onwards, the registers and the GTT are shared - * in the same BAR, so we want to restrict this ioremap from - * clobbering the GTT which we want ioremap_wc instead. Fortunately, - * the register BAR remains the same size for all the earlier - * generations up to Ironlake. - */ - if (info->gen < 5) - mmio_size = 512*1024; - else - mmio_size = 2*1024*1024; - - dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); - if (!dev_priv->regs) { - DRM_ERROR("failed to map registers\n"); - ret = -EIO; + ret = i915_mmio_setup(dev); + if (ret < 0) goto put_bridge; - } /* This must be called before any calls to HAS_PCH_* */ intel_detect_pch(dev); @@ -1047,8 +1071,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_irq_init(dev_priv); intel_uncore_sanitize(dev); - /* Try to make sure MCHBAR is enabled before poking at it */ - intel_setup_mchbar(dev); intel_opregion_setup(dev); i915_gem_load_init(dev); @@ -1129,7 +1151,7 @@ out_gtt: i915_global_gtt_cleanup(dev); out_uncore_fini: intel_uncore_fini(dev); - pci_iounmap(dev->pdev, dev_priv->regs); + i915_mmio_cleanup(dev); put_bridge: pci_dev_put(dev_priv->bridge_dev); i915_gem_load_cleanup(dev); @@ -1213,15 +1235,12 @@ int i915_driver_unload(struct drm_device *dev) intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); - intel_teardown_mchbar(dev); - pm_qos_remove_request(&dev_priv->pm_qos); i915_global_gtt_cleanup(dev); intel_uncore_fini(dev); - if (dev_priv->regs != NULL) - pci_iounmap(dev->pdev, dev_priv->regs); + i915_mmio_cleanup(dev); i915_gem_load_cleanup(dev); pci_dev_put(dev_priv->bridge_dev); -- cgit v0.10.2 From a4eba47b25c7077b5b1473b950ae2ff9bcf19fd5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 19 Jan 2016 15:26:32 +0200 Subject: drm/i915: Move stolen memory initialization earlier during loading The only device specific dependency of the stolen memory setup is the MMIO mapping and the stolen memory size. Both are already available in i915_gtt_init(), so move the stolen initialization to there. The clean-up code for i915_gtt_init() is in i915_global_gtt_cleanup(), so move the stolen memory clean-up code there too. This will be needed by an upcoming patch that needs the details of the memory we reserve, but the change is also part of our generic goal to move the initialization of resources with no or little dependencies on other device specific resources towards the beginning of the init sequence. Suggested-by: Chris Wilson Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1453209992-25995-8-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 697807d..db9b0c6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -391,13 +391,6 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_vga_client; - /* Initialise stolen first so that we may reserve preallocated - * objects for the BIOS to KMS transition. - */ - ret = i915_gem_init_stolen(dev); - if (ret) - goto cleanup_vga_switcheroo; - intel_power_domains_init_hw(dev_priv, false); intel_csr_ucode_init(dev_priv); @@ -460,8 +453,6 @@ cleanup_irq: intel_teardown_gmbus(dev); cleanup_csr: intel_csr_ucode_fini(dev_priv); - i915_gem_cleanup_stolen(dev); -cleanup_vga_switcheroo: vga_switcheroo_unregister_client(dev->pdev); cleanup_vga_client: vga_client_register(dev->pdev, NULL, NULL, NULL); @@ -1233,7 +1224,6 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); intel_fbc_cleanup_cfb(dev_priv); - i915_gem_cleanup_stolen(dev); pm_qos_remove_request(&dev_priv->pm_qos); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7377b67..2ccb2b5 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2809,6 +2809,8 @@ void i915_global_gtt_cleanup(struct drm_device *dev) ppgtt->base.cleanup(&ppgtt->base); } + i915_gem_cleanup_stolen(dev); + if (drm_mm_initialized(&vm->mm)) { if (intel_vgpu_active(dev)) intel_vgt_deballoon(); @@ -3181,6 +3183,14 @@ int i915_gem_gtt_init(struct drm_device *dev) if (ret) return ret; + /* + * Initialise stolen early so that we may reserve preallocated + * objects for the BIOS to KMS transition. + */ + ret = i915_gem_init_stolen(dev); + if (ret) + goto out_gtt_cleanup; + /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); @@ -3200,6 +3210,11 @@ int i915_gem_gtt_init(struct drm_device *dev) DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt); return 0; + +out_gtt_cleanup: + gtt->base.cleanup(&dev_priv->gtt.base); + + return ret; } void i915_gem_restore_gtt_mappings(struct drm_device *dev) -- cgit v0.10.2 From d9da6aa035c6dfdb003ff9776532b9b356d83f15 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 27 Jan 2016 13:41:09 +0000 Subject: drm/i915: Fix VCS ring selection after uapi decoupling This got broken in: commit de1add360522c876c25ef2bbbbab1c94bdb509ab Author: Tvrtko Ursulin Date: Fri Jan 15 15:12:50 2016 +0000 drm/i915: Decouple execbuf uAPI from internal implementation BSD ring flags need to be shifted before they can be considered indices into the ring array. Reported by Zhipeng Gong. v2: Simplify the code. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: Chris Wilson Cc: Zhipeng Gong Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1453902069-31353-1-git-send-email-tvrtko.ursulin@linux.intel.com Testcase: igt/gem_exec_basic # bdw-gt3 diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2dc08ce..5cb57f6 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1401,6 +1401,7 @@ eb_select_ring(struct drm_i915_private *dev_priv, bsd_idx = gen8_dispatch_bsd_ring(dev_priv, file); } else if (bsd_idx >= I915_EXEC_BSD_RING1 && bsd_idx <= I915_EXEC_BSD_RING2) { + bsd_idx >>= I915_EXEC_BSD_SHIFT; bsd_idx--; } else { DRM_DEBUG("execbuf with unknown bsd ring: %u\n", diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 6a19371..a5524cc 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -772,10 +772,12 @@ struct drm_i915_gem_execbuffer2 { #define I915_EXEC_HANDLE_LUT (1<<12) /** Used for switching BSD rings on the platforms with two BSD rings */ -#define I915_EXEC_BSD_MASK (3<<13) -#define I915_EXEC_BSD_DEFAULT (0<<13) /* default ping-pong mode */ -#define I915_EXEC_BSD_RING1 (1<<13) -#define I915_EXEC_BSD_RING2 (2<<13) +#define I915_EXEC_BSD_SHIFT (13) +#define I915_EXEC_BSD_MASK (3 << I915_EXEC_BSD_SHIFT) +/* default ping-pong mode */ +#define I915_EXEC_BSD_DEFAULT (0 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING1 (1 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING2 (2 << I915_EXEC_BSD_SHIFT) /** Tell the kernel that the batchbuffer is processed by * the resource streamer. -- cgit v0.10.2 From e5292823c142c9873d7d18cf34e7d97fd8a38f86 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 28 Jan 2016 10:29:54 +0000 Subject: drm/i915: Make LRC (un)pinning work on context and engine Previously intel_lr_context_(un)pin were operating on requests which is in conflict with their names. If we make them take a context and an engine, it makes the names make more sense and it also makes future fixes possible. v2: Rebase for default_context/kernel_context change. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Cc: Chris Wilson Cc: Nick Hoath diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c1bb6a6..a928823 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2680,7 +2680,7 @@ void i915_gem_request_free(struct kref *req_ref) if (ctx) { if (i915.enable_execlists && ctx != req->i915->kernel_context) - intel_lr_context_unpin(req); + intel_lr_context_unpin(ctx, req->ring); i915_gem_context_unreference(ctx); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index da97bc5..6c95aa1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -225,7 +225,8 @@ enum { #define GEN8_CTX_ID_SHIFT 32 #define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 -static int intel_lr_context_pin(struct drm_i915_gem_request *rq); +static int intel_lr_context_pin(struct intel_context *ctx, + struct intel_engine_cs *engine); static void lrc_setup_hardware_status_page(struct intel_engine_cs *ring, struct drm_i915_gem_object *default_ctx_obj); @@ -598,7 +599,7 @@ static int execlists_context_queue(struct drm_i915_gem_request *request) int num_elements = 0; if (request->ctx != request->i915->kernel_context) - intel_lr_context_pin(request); + intel_lr_context_pin(request->ctx, ring); i915_gem_request_reference(request); @@ -703,7 +704,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request } if (request->ctx != request->i915->kernel_context) - ret = intel_lr_context_pin(request); + ret = intel_lr_context_pin(request->ctx, request->ring); return ret; } @@ -1014,7 +1015,8 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring) ctx->engine[ring->id].state; if (ctx_obj && (ctx != req->i915->kernel_context)) - intel_lr_context_unpin(req); + intel_lr_context_unpin(ctx, ring); + list_del(&req->execlist_link); i915_gem_request_unreference(req); } @@ -1058,8 +1060,8 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) return 0; } -static int intel_lr_context_do_pin(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_lr_context_do_pin(struct intel_context *ctx, + struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1105,41 +1107,40 @@ unpin_ctx_obj: return ret; } -static int intel_lr_context_pin(struct drm_i915_gem_request *rq) +static int intel_lr_context_pin(struct intel_context *ctx, + struct intel_engine_cs *engine) { int ret = 0; - struct intel_engine_cs *ring = rq->ring; - if (rq->ctx->engine[ring->id].pin_count++ == 0) { - ret = intel_lr_context_do_pin(ring, rq->ctx); + if (ctx->engine[engine->id].pin_count++ == 0) { + ret = intel_lr_context_do_pin(ctx, engine); if (ret) goto reset_pin_count; } return ret; reset_pin_count: - rq->ctx->engine[ring->id].pin_count = 0; + ctx->engine[engine->id].pin_count = 0; return ret; } -void intel_lr_context_unpin(struct drm_i915_gem_request *rq) +void intel_lr_context_unpin(struct intel_context *ctx, + struct intel_engine_cs *engine) { - struct intel_engine_cs *ring = rq->ring; - struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; - struct intel_ringbuffer *ringbuf = rq->ringbuf; + struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; - WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&engine->dev->struct_mutex)); - if (!ctx_obj) + if (WARN_ON_ONCE(!ctx_obj)) return; - if (--rq->ctx->engine[ring->id].pin_count == 0) { - kunmap(kmap_to_page(rq->ctx->engine[ring->id].lrc_reg_state)); - intel_unpin_ringbuffer_obj(ringbuf); + if (--ctx->engine[engine->id].pin_count == 0) { + kunmap(kmap_to_page(ctx->engine[engine->id].lrc_reg_state)); + intel_unpin_ringbuffer_obj(ctx->engine[engine->id].ringbuf); i915_gem_object_ggtt_unpin(ctx_obj); - rq->ctx->engine[ring->id].lrc_vma = NULL; - rq->ctx->engine[ring->id].lrc_desc = 0; - rq->ctx->engine[ring->id].lrc_reg_state = NULL; + ctx->engine[engine->id].lrc_vma = NULL; + ctx->engine[engine->id].lrc_desc = 0; + ctx->engine[engine->id].lrc_reg_state = NULL; } } @@ -2064,7 +2065,7 @@ logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring) goto error; /* As this is the default context, always pin it */ - ret = intel_lr_context_do_pin(ring, dctx); + ret = intel_lr_context_do_pin(dctx, ring); if (ret) { DRM_ERROR( "Failed to pin and map ringbuffer %s: %d\n", diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 49af638..e6cda3e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -101,7 +101,8 @@ void intel_lr_context_free(struct intel_context *ctx); uint32_t intel_lr_context_size(struct intel_engine_cs *ring); int intel_lr_context_deferred_alloc(struct intel_context *ctx, struct intel_engine_cs *ring); -void intel_lr_context_unpin(struct drm_i915_gem_request *req); +void intel_lr_context_unpin(struct intel_context *ctx, + struct intel_engine_cs *engine); void intel_lr_context_reset(struct drm_device *dev, struct intel_context *ctx); uint64_t intel_lr_context_descriptor(struct intel_context *ctx, -- cgit v0.10.2 From 321fe304f1dd2dca025141b1d3211415af59020f Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 28 Jan 2016 10:29:55 +0000 Subject: drm/i915: Make LRC pinning own a reference to the context Will simplify the following fix and sounds logical. v2: Add some whitespace to separate logic better. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Cc: Chris Wilson Cc: Nick Hoath diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6c95aa1..61e64d7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1116,6 +1116,8 @@ static int intel_lr_context_pin(struct intel_context *ctx, ret = intel_lr_context_do_pin(ctx, engine); if (ret) goto reset_pin_count; + + i915_gem_context_reference(ctx); } return ret; @@ -1141,6 +1143,8 @@ void intel_lr_context_unpin(struct intel_context *ctx, ctx->engine[engine->id].lrc_vma = NULL; ctx->engine[engine->id].lrc_desc = 0; ctx->engine[engine->id].lrc_reg_state = NULL; + + i915_gem_context_unreference(ctx); } } -- cgit v0.10.2 From a0b4a6a8dbb147159602f0f82847ccd87bee5de8 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 28 Jan 2016 10:29:56 +0000 Subject: drm/i915: Extract context unpinning to its own function Will enable cleaner implementation of a following fix and easier code unification in the future. Idea and code by Chris Wilson. v2: Do not return before last_contexts on engines are unpinned. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Cc: Chris Wilson diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 6a4f64b..bba17b9 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -321,6 +321,14 @@ err_destroy: return ERR_PTR(ret); } +static void i915_gem_context_unpin(struct intel_context *ctx, + struct intel_engine_cs *engine) +{ + if (engine->id == RCS && ctx->legacy_hw_ctx.rcs_state) + i915_gem_object_ggtt_unpin(ctx->legacy_hw_ctx.rcs_state); + i915_gem_context_unreference(ctx); +} + void i915_gem_context_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -329,22 +337,15 @@ void i915_gem_context_reset(struct drm_device *dev) if (i915.enable_execlists) { struct intel_context *ctx; - list_for_each_entry(ctx, &dev_priv->context_list, link) { + list_for_each_entry(ctx, &dev_priv->context_list, link) intel_lr_context_reset(dev, ctx); - } - - return; } for (i = 0; i < I915_NUM_RINGS; i++) { struct intel_engine_cs *ring = &dev_priv->ring[i]; - struct intel_context *lctx = ring->last_context; - - if (lctx) { - if (lctx->legacy_hw_ctx.rcs_state && i == RCS) - i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state); - i915_gem_context_unreference(lctx); + if (ring->last_context) { + i915_gem_context_unpin(ring->last_context, ring); ring->last_context = NULL; } } @@ -417,13 +418,6 @@ void i915_gem_context_fini(struct drm_device *dev) * to offset the do_switch part, so that i915_gem_context_unreference() * can then free the base object correctly. */ WARN_ON(!dev_priv->ring[RCS].last_context); - if (dev_priv->ring[RCS].last_context == dctx) { - /* Fake switch to NULL context */ - WARN_ON(dctx->legacy_hw_ctx.rcs_state->active); - i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state); - i915_gem_context_unreference(dctx); - dev_priv->ring[RCS].last_context = NULL; - } i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state); } @@ -432,7 +426,7 @@ void i915_gem_context_fini(struct drm_device *dev) struct intel_engine_cs *ring = &dev_priv->ring[i]; if (ring->last_context) { - i915_gem_context_unreference(ring->last_context); + i915_gem_context_unpin(ring->last_context, ring); ring->last_context = NULL; } } -- cgit v0.10.2 From f4e2deceb6aaab661be3e13191cd13da3dd3b9c2 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 28 Jan 2016 10:29:57 +0000 Subject: drm/i915: Fix premature LRC unpin in GuC mode In GuC mode LRC pinning lifetime depends exclusively on the request liftime. Since that is terminated by the seqno update that opens up a race condition between GPU finishing writing out the context image and the driver unpinning the LRC. To extend the LRC lifetime we will employ a similar approach to what legacy ringbuffer submission does. We will start tracking the last submitted context per engine and keep it pinned until it is replaced by another one. Note that the driver unload path is a bit fragile and could benefit greatly from efforts to unify the legacy and exec list submission code paths. At the moment i915_gem_context_fini has special casing for the two which are potentialy not needed, and also depends on i915_gem_cleanup_ringbuffer running before itself. v2: * Move pinning into engine->emit_request and actually fix the reference/unreference logic. (Chris Wilson) * ring->dev can be NULL on driver unload so use a different route towards it. v3: * Rebase. * Handle the reset path. (Chris Wilson) * Exclude default context from the pinning - it is impossible to get it right before default context special casing in general is eliminated. v4: * Rebased & moved context tracking to intel_logical_ring_advance_and_submit. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Issue: VIZ-4277 Cc: Chris Wilson Cc: Nick Hoath Link: http://patchwork.freedesktop.org/patch/msgid/1453976997-25424-1-git-send-email-tvrtko.ursulin@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index bba17b9..83a097c 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -324,9 +324,13 @@ err_destroy: static void i915_gem_context_unpin(struct intel_context *ctx, struct intel_engine_cs *engine) { - if (engine->id == RCS && ctx->legacy_hw_ctx.rcs_state) - i915_gem_object_ggtt_unpin(ctx->legacy_hw_ctx.rcs_state); - i915_gem_context_unreference(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); + i915_gem_context_unreference(ctx); + } } void i915_gem_context_reset(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 61e64d7..3a03646 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -765,6 +765,7 @@ 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->ring; intel_logical_ring_advance(ringbuf); request->tail = ringbuf->tail; @@ -779,9 +780,20 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_advance(ringbuf); - if (intel_ring_stopped(request->ring)) + if (intel_ring_stopped(engine)) return 0; + if (engine->last_context != request->ctx) { + if (engine->last_context) + intel_lr_context_unpin(engine->last_context, engine); + if (request->ctx != request->i915->kernel_context) { + intel_lr_context_pin(request->ctx, engine); + engine->last_context = request->ctx; + } else { + engine->last_context = NULL; + } + } + if (dev_priv->guc.execbuf_client) i915_guc_submit(dev_priv->guc.execbuf_client, request); else @@ -1131,7 +1143,7 @@ void intel_lr_context_unpin(struct intel_context *ctx, { struct drm_i915_gem_object *ctx_obj = ctx->engine[engine->id].state; - WARN_ON(!mutex_is_locked(&engine->dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&ctx->i915->dev->struct_mutex)); if (WARN_ON_ONCE(!ctx_obj)) return; -- cgit v0.10.2 From 0aa498d59c67d925f2a53fdffd1d447727d65c22 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 28 Jan 2016 10:48:09 +0000 Subject: Fix pointer tests in error-handling paths In the error-handling paths of i915_gem_do_execbuffer() and intel_crtc_page_flip(), the local pointer-to-request variables were expected to be either valid pointers or NULL. Since 2682708 drm/i915: simplify allocation of driver-internal requests they could also be ERR_PTR() values, so the tests need to be updated to accommodate this case. Signed-off-by: Dave Gordon Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1453978089-29127-1-git-send-email-tvrtko.ursulin@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 5cb57f6..8fd00d2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1655,7 +1655,7 @@ err: * must be freed again. If it was submitted then it is being tracked * on the active request list and no clean up is required here. */ - if (ret && req) + if (ret && !IS_ERR_OR_NULL(req)) i915_gem_request_cancel(req); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8104511..b88cdac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11726,7 +11726,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_unpin: intel_unpin_fb_obj(fb, crtc->primary->state); cleanup_pending: - if (request) + if (!IS_ERR_OR_NULL(request)) i915_gem_request_cancel(request); atomic_dec(&intel_crtc->unpin_work_count); mutex_unlock(&dev->struct_mutex); -- cgit v0.10.2 From 7723f47dc685c7152d3ce217f09f036ec7f3f5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:22 +0200 Subject: drm/i915: Rename the rotated gtt view member to 'rotated' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also rename 'rotation_info' to 'rotated' to match the view type exactly, this should avoid confusion which union members is valid for each view type. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-2-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2ccb2b5..5b660ff 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3381,7 +3381,7 @@ static struct sg_table * intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, struct drm_i915_gem_object *obj) { - struct intel_rotation_info *rot_info = &ggtt_view->params.rotation_info; + struct intel_rotation_info *rot_info = &ggtt_view->params.rotated; unsigned int size_pages = rot_info->size >> PAGE_SHIFT; unsigned int size_pages_uv; struct sg_page_iter sg_iter; @@ -3613,7 +3613,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, if (view->type == I915_GGTT_VIEW_NORMAL) { return obj->base.size; } else if (view->type == I915_GGTT_VIEW_ROTATED) { - return view->params.rotation_info.size; + return view->params.rotated.size; } else if (view->type == I915_GGTT_VIEW_PARTIAL) { return view->params.partial.size << PAGE_SHIFT; } else { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index e573796..f520c90 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -155,7 +155,7 @@ struct i915_ggtt_view { u64 offset; unsigned int size; } partial; - struct intel_rotation_info rotation_info; + struct intel_rotation_info rotated; } params; struct sg_table *pages; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b88cdac..f54e119 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2284,7 +2284,7 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(fb->dev); - struct intel_rotation_info *info = &view->params.rotation_info; + struct intel_rotation_info *info = &view->params.rotated; unsigned int tile_size, tile_width, tile_height, cpp; *view = i915_ggtt_view_normal; @@ -2951,7 +2951,7 @@ u32 intel_plane_obj_offset(struct intel_plane *intel_plane, offset = vma->node.start; if (plane == 1) { - offset += vma->ggtt_view.params.rotation_info.uv_start_page * + offset += vma->ggtt_view.params.rotated.uv_start_page * PAGE_SIZE; } -- cgit v0.10.2 From 871302555b1dd19d91b8f78ae1d3790773098ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:23 +0200 Subject: drm/i915: Pass stride to rotate_pages() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass stride in addition to width and height to rotate_pages(). For now width and stride are the same, but once framebuffer offsets enter the scene that may no longer be the case. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-3-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5b660ff..b5aac6e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3348,6 +3348,7 @@ i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj, static struct scatterlist * rotate_pages(const dma_addr_t *in, unsigned int offset, unsigned int width, unsigned int height, + unsigned int stride, struct sg_table *st, struct scatterlist *sg) { unsigned int column, row; @@ -3359,7 +3360,7 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, } for (column = 0; column < width; column++) { - src_idx = width * (height - 1) + column; + src_idx = stride * (height - 1) + column; for (row = 0; row < height; row++) { st->nents++; /* We don't need the pages, but need to initialize @@ -3370,7 +3371,7 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, sg_dma_address(sg) = in[offset + src_idx]; sg_dma_len(sg) = PAGE_SIZE; sg = sg_next(sg); - src_idx -= width; + src_idx -= stride; } } @@ -3423,6 +3424,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, /* Rotate the pages. */ sg = rotate_pages(page_addr_list, 0, rot_info->width_pages, rot_info->height_pages, + rot_info->width_pages, st, NULL); /* Append the UV plane if NV12. */ @@ -3438,6 +3440,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, rotate_pages(page_addr_list, uv_start_page, rot_info->width_pages_uv, rot_info->height_pages_uv, + rot_info->width_pages_uv, st, sg); } -- cgit v0.10.2 From 11d23e6fa186f91cc6b1ccf27bbb14810c9baefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:24 +0200 Subject: drm/i915: Pass rotation_info to intel_rotate_fb_obj_pages() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_rotate_fb_obj_pages() doens't need the entire gtt view, just the rotation info suffices. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-4-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b5aac6e..715a771 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3379,10 +3379,9 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, } static struct sg_table * -intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, +intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info, struct drm_i915_gem_object *obj) { - struct intel_rotation_info *rot_info = &ggtt_view->params.rotated; unsigned int size_pages = rot_info->size >> PAGE_SHIFT; unsigned int size_pages_uv; struct sg_page_iter sg_iter; @@ -3522,7 +3521,7 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma) vma->ggtt_view.pages = vma->obj->pages; else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED) vma->ggtt_view.pages = - intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj); + intel_rotate_fb_obj_pages(&vma->ggtt_view.params.rotated, vma->obj); else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL) vma->ggtt_view.pages = intel_partial_pages(&vma->ggtt_view, vma->obj); -- cgit v0.10.2 From 54ea9da88fc89bbba0c2f888bdb265d9fd6a3945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:25 +0200 Subject: drm/i915: Make display gtt offsets u32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using 'unsigned long' for ggtt offsets doesn't make much sense. Use 'u32' instead since we've not yet seen a >4GiB ggtt. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-5-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f54e119..97af94a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2448,11 +2448,11 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel * is assumed to be a power-of-two. */ -unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv, - int *x, int *y, - uint64_t fb_modifier, - unsigned int cpp, - unsigned int pitch) +u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv, + int *x, int *y, + uint64_t fb_modifier, + unsigned int cpp, + unsigned int pitch) { if (fb_modifier != DRM_FORMAT_MOD_NONE) { unsigned int tile_size, tile_width, tile_height; @@ -2706,14 +2706,12 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, struct drm_framebuffer *fb = plane_state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); int plane = intel_crtc->plane; - unsigned long linear_offset; - int x = plane_state->src.x1 >> 16; - int y = plane_state->src.y1 >> 16; + u32 linear_offset; u32 dspcntr; i915_reg_t reg = DSPCNTR(plane); - int pixel_size; - - pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int x = plane_state->src.x1 >> 16; + int y = plane_state->src.y1 >> 16; dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -2839,7 +2837,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, struct drm_framebuffer *fb = plane_state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); int plane = intel_crtc->plane; - unsigned long linear_offset; + u32 linear_offset; u32 dspcntr; i915_reg_t reg = DSPCNTR(plane); int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bc97012..f620023 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -575,7 +575,7 @@ struct intel_crtc { /* Display surface base address adjustement for pageflips. Note that on * gen4+ this only adjusts up to a tile, offsets within a tile are * handled in the hw itself (with the TILEOFF register). */ - unsigned long dspaddr_offset; + u32 dspaddr_offset; int adjusted_x; int adjusted_y; @@ -1172,11 +1172,11 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv, - int *x, int *y, - uint64_t fb_modifier, - unsigned int cpp, - unsigned int pitch); +u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv, + int *x, int *y, + uint64_t fb_modifier, + unsigned int cpp, + unsigned int pitch); void intel_prepare_reset(struct drm_device *dev); void intel_finish_reset(struct drm_device *dev); void hsw_enable_pc8(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0875c8e..f1ee7db 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -350,7 +350,7 @@ vlv_update_plane(struct drm_plane *dplane, int pipe = intel_plane->pipe; int plane = intel_plane->plane; u32 sprctl; - unsigned long sprsurf_offset, linear_offset; + u32 sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; @@ -493,7 +493,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_i915_gem_object *obj = intel_fb_obj(fb); enum pipe pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; - unsigned long sprsurf_offset, linear_offset; + u32 sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; @@ -635,8 +635,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb = plane_state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); int pipe = intel_plane->pipe; - unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; + u32 dvssurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; -- cgit v0.10.2 From ac484963f979b6ab490183f0e09a3a17175f5758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:26 +0200 Subject: drm/i915: Standardize on 'cpp' for bytes per pixel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We more or less randomly call the "bytes per pixel" value 'cpp', 'bytes_per_pixel', 'pixel_size', or even 'bpp'. Let's just pick one and stick to it. I've chosen 'cpp'. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-6-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 97af94a..23cce7d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2709,7 +2709,7 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, u32 linear_offset; u32 dspcntr; i915_reg_t reg = DSPCNTR(plane); - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); int x = plane_state->src.x1 >> 16; int y = plane_state->src.y1 >> 16; @@ -2769,13 +2769,12 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, if (IS_G4X(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - linear_offset = y * fb->pitches[0] + x * pixel_size; + linear_offset = y * fb->pitches[0] + x * cpp; if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = intel_compute_tile_offset(dev_priv, &x, &y, - fb->modifier[0], - pixel_size, + fb->modifier[0], cpp, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; } else { @@ -2792,7 +2791,7 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, data and adding to linear_offset*/ linear_offset += (crtc_state->pipe_src_h - 1) * fb->pitches[0] + - (crtc_state->pipe_src_w - 1) * pixel_size; + (crtc_state->pipe_src_w - 1) * cpp; } intel_crtc->adjusted_x = x; @@ -2840,7 +2839,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, u32 linear_offset; u32 dspcntr; i915_reg_t reg = DSPCNTR(plane); - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); int x = plane_state->src.x1 >> 16; int y = plane_state->src.y1 >> 16; @@ -2879,11 +2878,10 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - linear_offset = y * fb->pitches[0] + x * pixel_size; + linear_offset = y * fb->pitches[0] + x * cpp; intel_crtc->dspaddr_offset = intel_compute_tile_offset(dev_priv, &x, &y, - fb->modifier[0], - pixel_size, + fb->modifier[0], cpp, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) { @@ -2897,7 +2895,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, data and adding to linear_offset*/ linear_offset += (crtc_state->pipe_src_h - 1) * fb->pitches[0] + - (crtc_state->pipe_src_w - 1) * pixel_size; + (crtc_state->pipe_src_w - 1) * cpp; } } @@ -14682,10 +14680,12 @@ u32 intel_fb_pitch_limit(struct drm_device *dev, uint64_t fb_modifier, u32 gen = INTEL_INFO(dev)->gen; if (gen >= 9) { + int cpp = drm_format_plane_cpp(pixel_format, 0); + /* "The stride in bytes must not exceed the of the size of 8K * pixels and 32K bytes." */ - return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768); + return min(8192 * cpp, 32768); } else if (gen >= 5 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { return 32*1024; } else if (gen >= 4) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 20bf854..31bc4ea 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -548,7 +548,7 @@ static const struct intel_watermark_params i845_wm_info = { * intel_calculate_wm - calculate watermark level * @clock_in_khz: pixel clock * @wm: chip FIFO params - * @pixel_size: display pixel size + * @cpp: bytes per pixel * @latency_ns: memory latency for the platform * * Calculate the watermark level (the level at which the display plane will @@ -564,8 +564,7 @@ static const struct intel_watermark_params i845_wm_info = { */ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, const struct intel_watermark_params *wm, - int fifo_size, - int pixel_size, + int fifo_size, int cpp, unsigned long latency_ns) { long entries_required, wm_size; @@ -576,7 +575,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, * clocks go from a few thousand to several hundred thousand. * latency is usually a few thousand */ - entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / + entries_required = ((clock_in_khz / 1000) * cpp * latency_ns) / 1000; entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size); @@ -640,13 +639,13 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) crtc = single_enabled_crtc(dev); if (crtc) { const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode; - int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8; + int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); int clock = adjusted_mode->crtc_clock; /* Display SR */ wm = intel_calculate_wm(clock, &pineview_display_wm, pineview_display_wm.fifo_size, - pixel_size, latency->display_sr); + cpp, latency->display_sr); reg = I915_READ(DSPFW1); reg &= ~DSPFW_SR_MASK; reg |= FW_WM(wm, SR); @@ -656,7 +655,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) /* cursor SR */ wm = intel_calculate_wm(clock, &pineview_cursor_wm, pineview_display_wm.fifo_size, - pixel_size, latency->cursor_sr); + cpp, latency->cursor_sr); reg = I915_READ(DSPFW3); reg &= ~DSPFW_CURSOR_SR_MASK; reg |= FW_WM(wm, CURSOR_SR); @@ -665,7 +664,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) /* Display HPLL off SR */ wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->display_hpll_disable); + cpp, latency->display_hpll_disable); reg = I915_READ(DSPFW3); reg &= ~DSPFW_HPLL_SR_MASK; reg |= FW_WM(wm, HPLL_SR); @@ -674,7 +673,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) /* cursor HPLL off SR */ wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->cursor_hpll_disable); + cpp, latency->cursor_hpll_disable); reg = I915_READ(DSPFW3); reg &= ~DSPFW_HPLL_CURSOR_MASK; reg |= FW_WM(wm, HPLL_CURSOR); @@ -698,7 +697,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, { struct drm_crtc *crtc; const struct drm_display_mode *adjusted_mode; - int htotal, hdisplay, clock, pixel_size; + int htotal, hdisplay, clock, cpp; int line_time_us, line_count; int entries, tlb_miss; @@ -713,10 +712,10 @@ static bool g4x_compute_wm0(struct drm_device *dev, clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->crtc_htotal; hdisplay = to_intel_crtc(crtc)->config->pipe_src_w; - pixel_size = crtc->primary->state->fb->bits_per_pixel / 8; + cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); /* Use the small buffer method to calculate plane watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + entries = ((clock * cpp / 1000) * display_latency_ns) / 1000; tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; if (tlb_miss > 0) entries += tlb_miss; @@ -728,7 +727,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, /* Use the large buffer method to calculate cursor watermark */ line_time_us = max(htotal * 1000 / clock, 1); line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; - entries = line_count * crtc->cursor->state->crtc_w * pixel_size; + entries = line_count * crtc->cursor->state->crtc_w * cpp; tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; if (tlb_miss > 0) entries += tlb_miss; @@ -784,7 +783,7 @@ static bool g4x_compute_srwm(struct drm_device *dev, { struct drm_crtc *crtc; const struct drm_display_mode *adjusted_mode; - int hdisplay, htotal, pixel_size, clock; + int hdisplay, htotal, cpp, clock; unsigned long line_time_us; int line_count, line_size; int small, large; @@ -800,21 +799,21 @@ static bool g4x_compute_srwm(struct drm_device *dev, clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->crtc_htotal; hdisplay = to_intel_crtc(crtc)->config->pipe_src_w; - pixel_size = crtc->primary->state->fb->bits_per_pixel / 8; + cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); line_time_us = max(htotal * 1000 / clock, 1); line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; + line_size = hdisplay * cpp; /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + small = ((clock * cpp / 1000) * latency_ns) / 1000; large = line_count * line_size; entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); *display_wm = entries + display->guard_size; /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * crtc->cursor->state->crtc_w; + entries = line_count * cpp * crtc->cursor->state->crtc_w; entries = DIV_ROUND_UP(entries, cursor->cacheline_size); *cursor_wm = entries + cursor->guard_size; @@ -906,13 +905,13 @@ enum vlv_wm_level { static unsigned int vlv_wm_method2(unsigned int pixel_rate, unsigned int pipe_htotal, unsigned int horiz_pixels, - unsigned int bytes_per_pixel, + unsigned int cpp, unsigned int latency) { unsigned int ret; ret = (latency * pixel_rate) / (pipe_htotal * 10000); - ret = (ret + 1) * horiz_pixels * bytes_per_pixel; + ret = (ret + 1) * horiz_pixels * cpp; ret = DIV_ROUND_UP(ret, 64); return ret; @@ -941,7 +940,7 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane, int level) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - int clock, htotal, pixel_size, width, wm; + int clock, htotal, cpp, width, wm; if (dev_priv->wm.pri_latency[level] == 0) return USHRT_MAX; @@ -949,7 +948,7 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane, if (!state->visible) return 0; - pixel_size = drm_format_plane_cpp(state->base.fb->pixel_format, 0); + cpp = drm_format_plane_cpp(state->base.fb->pixel_format, 0); clock = crtc->config->base.adjusted_mode.crtc_clock; htotal = crtc->config->base.adjusted_mode.crtc_htotal; width = crtc->config->pipe_src_w; @@ -965,7 +964,7 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane, */ wm = 63; } else { - wm = vlv_wm_method2(clock, htotal, width, pixel_size, + wm = vlv_wm_method2(clock, htotal, width, cpp, dev_priv->wm.pri_latency[level] * 10); } @@ -1439,7 +1438,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w; - int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8; + int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); unsigned long line_time_us; int entries; @@ -1447,7 +1446,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) /* Use ns/us then divide to preserve precision */ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; + cpp * hdisplay; entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE); srwm = I965_FIFO_SIZE - entries; if (srwm < 0) @@ -1457,7 +1456,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) entries, srwm); entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * crtc->cursor->state->crtc_w; + cpp * crtc->cursor->state->crtc_w; entries = DIV_ROUND_UP(entries, i965_cursor_wm_info.cacheline_size); cursor_sr = i965_cursor_wm_info.fifo_size - @@ -1518,7 +1517,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) crtc = intel_get_crtc_for_plane(dev, 0); if (intel_crtc_active(crtc)) { const struct drm_display_mode *adjusted_mode; - int cpp = crtc->primary->state->fb->bits_per_pixel / 8; + int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); if (IS_GEN2(dev)) cpp = 4; @@ -1540,7 +1539,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) crtc = intel_get_crtc_for_plane(dev, 1); if (intel_crtc_active(crtc)) { const struct drm_display_mode *adjusted_mode; - int cpp = crtc->primary->state->fb->bits_per_pixel / 8; + int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0); if (IS_GEN2(dev)) cpp = 4; @@ -1586,7 +1585,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w; - int pixel_size = enabled->primary->state->fb->bits_per_pixel / 8; + int cpp = drm_format_plane_cpp(enabled->primary->state->fb->pixel_format, 0); unsigned long line_time_us; int entries; @@ -1594,7 +1593,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) /* Use ns/us then divide to preserve precision */ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; + cpp * hdisplay; entries = DIV_ROUND_UP(entries, wm_info->cacheline_size); DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); srwm = wm_info->fifo_size - entries; @@ -1685,15 +1684,14 @@ uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config) } /* latency must be in 0.1us units. */ -static uint32_t ilk_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel, - uint32_t latency) +static uint32_t ilk_wm_method1(uint32_t pixel_rate, uint8_t cpp, uint32_t latency) { uint64_t ret; if (WARN(latency == 0, "Latency value missing\n")) return UINT_MAX; - ret = (uint64_t) pixel_rate * bytes_per_pixel * latency; + ret = (uint64_t) pixel_rate * cpp * latency; ret = DIV_ROUND_UP_ULL(ret, 64 * 10000) + 2; return ret; @@ -1701,7 +1699,7 @@ static uint32_t ilk_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel, /* latency must be in 0.1us units. */ static uint32_t ilk_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, - uint32_t horiz_pixels, uint8_t bytes_per_pixel, + uint32_t horiz_pixels, uint8_t cpp, uint32_t latency) { uint32_t ret; @@ -1712,13 +1710,13 @@ static uint32_t ilk_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, return UINT_MAX; ret = (latency * pixel_rate) / (pipe_htotal * 10000); - ret = (ret + 1) * horiz_pixels * bytes_per_pixel; + ret = (ret + 1) * horiz_pixels * cpp; ret = DIV_ROUND_UP(ret, 64) + 2; return ret; } static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, - uint8_t bytes_per_pixel) + uint8_t cpp) { /* * Neither of these should be possible since this function shouldn't be @@ -1726,12 +1724,12 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, * extra paranoid to avoid a potential divide-by-zero if we screw up * elsewhere in the driver. */ - if (WARN_ON(!bytes_per_pixel)) + if (WARN_ON(!cpp)) return 0; if (WARN_ON(!horiz_pixels)) return 0; - return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; + return DIV_ROUND_UP(pri_val * 64, horiz_pixels * cpp) + 2; } struct ilk_wm_maximums { @@ -1750,13 +1748,14 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate, uint32_t mem_value, bool is_lp) { - int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + int cpp = pstate->base.fb ? + drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0; uint32_t method1, method2; if (!cstate->base.active || !pstate->visible) return 0; - method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value); + method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value); if (!is_lp) return method1; @@ -1764,8 +1763,7 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate, method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate), cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), - bpp, - mem_value); + cpp, mem_value); return min(method1, method2); } @@ -1778,18 +1776,18 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value) { - int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + int cpp = pstate->base.fb ? + drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0; uint32_t method1, method2; if (!cstate->base.active || !pstate->visible) return 0; - method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value); + method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), cpp, mem_value); method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate), cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), - bpp, - mem_value); + cpp, mem_value); return min(method1, method2); } @@ -1801,7 +1799,8 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value) { - int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + int cpp = pstate->base.fb ? + drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0; if (!cstate->base.active || !pstate->visible) return 0; @@ -1809,8 +1808,7 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, return ilk_wm_method2(ilk_pipe_pixel_rate(cstate), cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), - bpp, - mem_value); + cpp, mem_value); } /* Only for WM_LP. */ @@ -1818,12 +1816,13 @@ static uint32_t ilk_compute_fbc_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t pri_val) { - int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + int cpp = pstate->base.fb ? + drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0; if (!cstate->base.active || !pstate->visible) return 0; - return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), bpp); + return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), cpp); } static unsigned int ilk_display_fifo_size(const struct drm_device *dev) @@ -3042,26 +3041,25 @@ static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_state *config) /* * The max latency should be 257 (max the punit can code is 255 and we add 2us - * for the read latency) and bytes_per_pixel should always be <= 8, so that + * for the read latency) and cpp should always be <= 8, so that * should allow pixel_rate up to ~2 GHz which seems sufficient since max * 2xcdclk is 1350 MHz and the pixel rate should never exceed that. */ -static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel, - uint32_t latency) +static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t cpp, uint32_t latency) { uint32_t wm_intermediate_val, ret; if (latency == 0) return UINT_MAX; - wm_intermediate_val = latency * pixel_rate * bytes_per_pixel / 512; + wm_intermediate_val = latency * pixel_rate * cpp / 512; ret = DIV_ROUND_UP(wm_intermediate_val, 1000); return ret; } static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, - uint32_t horiz_pixels, uint8_t bytes_per_pixel, + uint32_t horiz_pixels, uint8_t cpp, uint64_t tiling, uint32_t latency) { uint32_t ret; @@ -3071,7 +3069,7 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, if (latency == 0) return UINT_MAX; - plane_bytes_per_line = horiz_pixels * bytes_per_pixel; + plane_bytes_per_line = horiz_pixels * cpp; if (tiling == I915_FORMAT_MOD_Y_TILED || tiling == I915_FORMAT_MOD_Yf_TILED) { @@ -3121,23 +3119,21 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t plane_bytes_per_line, plane_blocks_per_line; uint32_t res_blocks, res_lines; uint32_t selected_result; - uint8_t bytes_per_pixel; + uint8_t cpp; if (latency == 0 || !cstate->base.active || !fb) return false; - bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0); + cpp = drm_format_plane_cpp(fb->pixel_format, 0); method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate), - bytes_per_pixel, - latency); + cpp, latency); method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate), cstate->base.adjusted_mode.crtc_htotal, cstate->pipe_src_w, - bytes_per_pixel, - fb->modifier[0], + cpp, fb->modifier[0], latency); - plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel; + plane_bytes_per_line = cstate->pipe_src_w * cpp; plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512); if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || @@ -3145,11 +3141,11 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t min_scanlines = 4; uint32_t y_tile_minimum; if (intel_rotation_90_or_270(plane->state->rotation)) { - int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ? + int cpp = (fb->pixel_format == DRM_FORMAT_NV12) ? drm_format_plane_cpp(fb->pixel_format, 1) : drm_format_plane_cpp(fb->pixel_format, 0); - switch (bpp) { + switch (cpp) { case 1: min_scanlines = 16; break; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f1ee7db..a2582c4 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -351,7 +351,7 @@ vlv_update_plane(struct drm_plane *dplane, int plane = intel_plane->plane; u32 sprctl; u32 sprsurf_offset, linear_offset; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; int crtc_y = plane_state->dst.y1; @@ -422,10 +422,9 @@ vlv_update_plane(struct drm_plane *dplane, crtc_w--; crtc_h--; - linear_offset = y * fb->pitches[0] + x * pixel_size; + linear_offset = y * fb->pitches[0] + x * cpp; sprsurf_offset = intel_compute_tile_offset(dev_priv, &x, &y, - fb->modifier[0], - pixel_size, + fb->modifier[0], cpp, fb->pitches[0]); linear_offset -= sprsurf_offset; @@ -434,7 +433,7 @@ vlv_update_plane(struct drm_plane *dplane, x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + linear_offset += src_h * fb->pitches[0] + src_w * cpp; } if (key->flags) { @@ -494,7 +493,7 @@ ivb_update_plane(struct drm_plane *plane, enum pipe pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; u32 sprsurf_offset, linear_offset; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; int crtc_y = plane_state->dst.y1; @@ -556,10 +555,9 @@ ivb_update_plane(struct drm_plane *plane, if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - linear_offset = y * fb->pitches[0] + x * pixel_size; + linear_offset = y * fb->pitches[0] + x * cpp; sprsurf_offset = intel_compute_tile_offset(dev_priv, &x, &y, - fb->modifier[0], - pixel_size, + fb->modifier[0], cpp, fb->pitches[0]); linear_offset -= sprsurf_offset; @@ -570,8 +568,7 @@ ivb_update_plane(struct drm_plane *plane, if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + - src_w * pixel_size; + linear_offset += src_h * fb->pitches[0] + src_w * cpp; } } @@ -637,7 +634,7 @@ ilk_update_plane(struct drm_plane *plane, int pipe = intel_plane->pipe; u32 dvscntr, dvsscale; u32 dvssurf_offset, linear_offset; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->dst.x1; int crtc_y = plane_state->dst.y1; @@ -695,10 +692,9 @@ ilk_update_plane(struct drm_plane *plane, if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; - linear_offset = y * fb->pitches[0] + x * pixel_size; + linear_offset = y * fb->pitches[0] + x * cpp; dvssurf_offset = intel_compute_tile_offset(dev_priv, &x, &y, - fb->modifier[0], - pixel_size, + fb->modifier[0], cpp, fb->pitches[0]); linear_offset -= dvssurf_offset; @@ -707,7 +703,7 @@ ilk_update_plane(struct drm_plane *plane, x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + linear_offset += src_h * fb->pitches[0] + src_w * cpp; } if (key->flags) { @@ -772,7 +768,6 @@ intel_check_sprite_plane(struct drm_plane *plane, int hscale, vscale; int max_scale, min_scale; bool can_scale; - int pixel_size; if (!fb) { state->visible = false; @@ -894,6 +889,7 @@ intel_check_sprite_plane(struct drm_plane *plane, /* Check size restrictions when scaling */ if (state->visible && (src_w != crtc_w || src_h != crtc_h)) { unsigned int width_bytes; + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); WARN_ON(!can_scale); @@ -905,9 +901,7 @@ intel_check_sprite_plane(struct drm_plane *plane, if (src_w < 3 || src_h < 3) state->visible = false; - pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - width_bytes = ((src_x * pixel_size) & 63) + - src_w * pixel_size; + width_bytes = ((src_x * cpp) & 63) + src_w * cpp; if (INTEL_INFO(dev)->gen < 9 && (src_w > 2048 || src_h > 2048 || width_bytes > 4096 || fb->pitches[0] > 4096)) { -- cgit v0.10.2 From b16bb01fd2d599ba5cbc031b2c5318eba29efbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Jan 2016 21:05:28 +0200 Subject: drm/i915: Fix intel_tile_width() parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fb_modifiers and cpp arguments passed to intel_tile_width() in intel_fill_fb_ggtt_view() got accidentally swapped around. I'm pretty sure I fixed this already, but could be I lost the fix accidentally during some rebases or something. Anyway, fix it up for real. Fixes: d9b3288ecf2f ("drm/i915: change intel_fill_fb_ggtt_view() to use the real tile size") Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1453316739-13296-8-git-send-email-ville.syrjala@linux.intel.com Testcase: igt/kms_rotation_crc/primary-rotation-90 Reviewed-by: Daniel Vetter Cc: drm-intel-fixes@lists.freedesktop.org diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 23cce7d..304fc96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2306,7 +2306,7 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, tile_size = intel_tile_size(dev_priv); cpp = drm_format_plane_cpp(fb->pixel_format, 0); - tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]); + tile_width = intel_tile_width(dev_priv, fb->modifier[0], cpp); tile_height = tile_size / tile_width; info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width); -- cgit v0.10.2 From 1e859111c128265f8d62b39ff322e42b1ddb5a20 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Jan 2016 12:02:28 +0100 Subject: drm/i915: refine qemu south bridge detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test for the qemu q35 south bridge added by commit "39bfcd52 drm/i915: more virtual south bridge detection" also matches on real hardware. Having the check for virtual systems last in the list is not enough to avoid that ... Refine the check by additionally verifying the pci subsystem id to see whenever it *really* is qemu. [ v2: fix subvendor tyops ] Reported-and-tested-by: Bjørn Mork Signed-off-by: Gerd Hoffmann Tested-by: Bruno Wolff III Cc: drm-intel-fixes@lists.freedesktop.org Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1453719748-10944-1-git-send-email-kraxel@redhat.com diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 706b8ea..11d8414 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -501,7 +501,9 @@ void intel_detect_pch(struct drm_device *dev) WARN_ON(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev)); } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || - (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE)) { + ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && + pch->subsystem_vendor == 0x1af4 && + pch->subsystem_device == 0x1100)) { dev_priv->pch_type = intel_virt_detect_pch(dev); } else continue; -- cgit v0.10.2 From bbc396993a97246403f5979036f1b4637a56ef72 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Thu, 28 Jan 2016 15:22:05 -0800 Subject: drm/i915: Fix file permissions No functional change Signed-off-by: Mat Martineau Fixes: f8d03ea0053b ("drm/i915: increase the tries for HDMI hotplug live status checking") Link: http://patchwork.freedesktop.org/patch/msgid/1454023325-26265-1-git-send-email-mathew.j.martineau@linux.intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c old mode 100755 new mode 100644 -- cgit v0.10.2 From ca18d51d77eba6120f56761e5a0e541dbb07fa50 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Jan 2016 18:03:05 -0200 Subject: drm/i915/fbc: wait for a vblank instead of 50ms when enabling Instead of waiting for 50ms, just wait until the next vblank, since it's the minimum requirement. The whole infrastructure of FBC is based on vblanks, so waiting for X vblanks instead of X milliseconds sounds like the correct way to go. Besides, 50ms may be less than a vblank on super slow modes that may or may not exist. There are some small improvements in PC state residency (due to the fact that we're now using 16ms for the common modes instead of 50ms), but the biggest advantage is still the correctness of being vblank-based instead of time-based. v2: - Rebase after changing the patch order. - Update the commit message. v3: - Fix bogus vblank_get() instead of vblank_count() (Ville). - Don't forget to call drm_crtc_vblank_{get,put} (Chris, Ville) - Adjust the performance details on the commit message. v4: - Don't grab the FBC mutex just to grab the vblank (Maarten) Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Link: http://patchwork.freedesktop.org/patch/msgid/1453406585-10233-1-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 905e90f..83b629b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -921,9 +921,9 @@ struct i915_fbc { struct intel_fbc_work { bool scheduled; + u32 scheduled_vblank; struct work_struct work; struct drm_framebuffer *fb; - unsigned long enable_jiffies; } work; const char *no_fbc_reason; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a1988a4..3993b43 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -381,7 +381,17 @@ static void intel_fbc_work_fn(struct work_struct *__work) container_of(__work, struct drm_i915_private, fbc.work.work); struct intel_fbc_work *work = &dev_priv->fbc.work; struct intel_crtc *crtc = dev_priv->fbc.crtc; - int delay_ms = 50; + struct drm_vblank_crtc *vblank = &dev_priv->dev->vblank[crtc->pipe]; + + if (drm_crtc_vblank_get(&crtc->base)) { + DRM_ERROR("vblank not available for FBC on pipe %c\n", + pipe_name(crtc->pipe)); + + mutex_lock(&dev_priv->fbc.lock); + work->scheduled = false; + mutex_unlock(&dev_priv->fbc.lock); + return; + } retry: /* Delay the actual enabling to let pageflipping cease and the @@ -390,14 +400,16 @@ retry: * vblank to pass after disabling the FBC before we attempt * to modify the control registers. * - * A more complicated solution would involve tracking vblanks - * following the termination of the page-flipping sequence - * and indeed performing the enable as a co-routine and not - * waiting synchronously upon the vblank. - * * WaFbcWaitForVBlankBeforeEnable:ilk,snb + * + * It is also worth mentioning that since work->scheduled_vblank can be + * updated multiple times by the other threads, hitting the timeout is + * not an error condition. We'll just end up hitting the "goto retry" + * case below. */ - wait_remaining_ms_from_jiffies(work->enable_jiffies, delay_ms); + wait_event_timeout(vblank->queue, + drm_crtc_vblank_count(&crtc->base) != work->scheduled_vblank, + msecs_to_jiffies(50)); mutex_lock(&dev_priv->fbc.lock); @@ -406,8 +418,7 @@ retry: goto out; /* Were we delayed again while this function was sleeping? */ - if (time_after(work->enable_jiffies + msecs_to_jiffies(delay_ms), - jiffies)) { + if (drm_crtc_vblank_count(&crtc->base) == work->scheduled_vblank) { mutex_unlock(&dev_priv->fbc.lock); goto retry; } @@ -419,6 +430,7 @@ retry: out: mutex_unlock(&dev_priv->fbc.lock); + drm_crtc_vblank_put(&crtc->base); } static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) @@ -434,13 +446,20 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + if (drm_crtc_vblank_get(&crtc->base)) { + DRM_ERROR("vblank not available for FBC on pipe %c\n", + pipe_name(crtc->pipe)); + return; + } + /* It is useless to call intel_fbc_cancel_work() in this function since * we're not releasing fbc.lock, so it won't have an opportunity to grab * it to discover that it was cancelled. So we just update the expected * jiffy count. */ work->fb = crtc->base.primary->fb; work->scheduled = true; - work->enable_jiffies = jiffies; + work->scheduled_vblank = drm_crtc_vblank_count(&crtc->base); + drm_crtc_vblank_put(&crtc->base); schedule_work(&work->work); } -- cgit v0.10.2 From 615b40d7e441ee10b859ccc5a3e456c823f42cfa Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:35 -0200 Subject: drm/i915/fbc: extract intel_fbc_can_activate() Extract all the code that checks if the FBC configuration is valid to its own function, making __intel_fbc_update() much simpler. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-3-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 3993b43..1440bb3 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -516,17 +516,6 @@ static bool crtc_can_fbc(struct intel_crtc *crtc) return true; } -static bool crtc_is_valid(struct intel_crtc *crtc) -{ - if (!intel_crtc_active(&crtc->base)) - return false; - - if (!to_intel_plane_state(crtc->base.primary->state)->visible) - return false; - - return true; -} - static bool multiple_pipes_ok(struct drm_i915_private *dev_priv) { enum pipe pipe; @@ -752,48 +741,40 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) return effective_w <= max_w && effective_h <= max_h; } -/** - * __intel_fbc_update - activate/deactivate FBC as needed, unlocked - * @crtc: the CRTC that triggered the update - * - * This function completely reevaluates the status of FBC, then activates, - * deactivates or maintains it on the same state. - */ -static void __intel_fbc_update(struct intel_crtc *crtc) +static bool intel_fbc_can_activate(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_plane *primary; struct drm_framebuffer *fb; + struct intel_plane_state *plane_state; struct drm_i915_gem_object *obj; const struct drm_display_mode *adjusted_mode; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - - if (!multiple_pipes_ok(dev_priv)) { - set_no_fbc_reason(dev_priv, "more than one pipe active"); - goto out_disable; - } - - if (!dev_priv->fbc.enabled || dev_priv->fbc.crtc != crtc) - return; - - if (!crtc_is_valid(crtc)) { - set_no_fbc_reason(dev_priv, "no output"); - goto out_disable; + if (!intel_crtc_active(&crtc->base)) { + set_no_fbc_reason(dev_priv, "CRTC not active"); + return false; } - fb = crtc->base.primary->fb; + primary = crtc->base.primary; + fb = primary->fb; obj = intel_fb_obj(fb); adjusted_mode = &crtc->config->base.adjusted_mode; + plane_state = to_intel_plane_state(primary->state); + + if (!plane_state->visible) { + set_no_fbc_reason(dev_priv, "primary plane not visible"); + return false; + } if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { set_no_fbc_reason(dev_priv, "incompatible mode"); - goto out_disable; + return false; } if (!intel_fbc_hw_tracking_covers_screen(crtc)) { set_no_fbc_reason(dev_priv, "mode too large for compression"); - goto out_disable; + return false; } /* The use of a CPU fence is mandatory in order to detect writes @@ -802,22 +783,22 @@ static void __intel_fbc_update(struct intel_crtc *crtc) if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced"); - goto out_disable; + return false; } if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && - crtc->base.primary->state->rotation != BIT(DRM_ROTATE_0)) { + plane_state->base.rotation != BIT(DRM_ROTATE_0)) { set_no_fbc_reason(dev_priv, "rotation unsupported"); - goto out_disable; + return false; } if (!stride_is_valid(dev_priv, fb->pitches[0])) { set_no_fbc_reason(dev_priv, "framebuffer stride not supported"); - goto out_disable; + return false; } if (!pixel_format_is_valid(fb)) { set_no_fbc_reason(dev_priv, "pixel format is invalid"); - goto out_disable; + return false; } /* WaFbcExceedCdClockThreshold:hsw,bdw */ @@ -825,7 +806,7 @@ static void __intel_fbc_update(struct intel_crtc *crtc) ilk_pipe_pixel_rate(crtc->config) >= dev_priv->cdclk_freq * 95 / 100) { set_no_fbc_reason(dev_priv, "pixel rate is too big"); - goto out_disable; + return false; } /* It is possible for the required CFB size change without a @@ -841,16 +822,43 @@ static void __intel_fbc_update(struct intel_crtc *crtc) if (intel_fbc_calculate_cfb_size(crtc, fb) > dev_priv->fbc.compressed_fb.size * dev_priv->fbc.threshold) { set_no_fbc_reason(dev_priv, "CFB requirements changed"); + return false; + } + + return true; +} + +/** + * __intel_fbc_update - activate/deactivate FBC as needed, unlocked + * @crtc: the CRTC that triggered the update + * + * This function completely reevaluates the status of FBC, then activates, + * deactivates or maintains it on the same state. + */ +static void __intel_fbc_update(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + + if (!multiple_pipes_ok(dev_priv)) { + set_no_fbc_reason(dev_priv, "more than one pipe active"); goto out_disable; } + if (!dev_priv->fbc.enabled || dev_priv->fbc.crtc != crtc) + return; + + if (!intel_fbc_can_activate(crtc)) + goto out_disable; + /* If the scanout has not changed, don't modify the FBC settings. * Note that we make the fundamental assumption that the fb->obj * cannot be unpinned (and have its GTT offset and fence revoked) * without first being decoupled from the scanout and FBC disabled. */ if (dev_priv->fbc.crtc == crtc && - dev_priv->fbc.fb_id == fb->base.id && + dev_priv->fbc.fb_id == crtc->base.primary->fb->base.id && dev_priv->fbc.y == crtc->base.y && dev_priv->fbc.active) return; -- cgit v0.10.2 From 44a8a257087bf5deb8c77bbb640cf0a15643b017 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:36 -0200 Subject: drm/i915/fbc: extract intel_fbc_can_enable() Make our enable/activate checking model more explicit, especially since we now have intel_fbc_can_activate(). Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-4-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 1440bb3..f76b158 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -828,6 +828,33 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) return true; } +static bool intel_fbc_can_enable(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (intel_vgpu_active(dev_priv->dev)) { + set_no_fbc_reason(dev_priv, "VGPU is active"); + return false; + } + + if (i915.enable_fbc < 0) { + set_no_fbc_reason(dev_priv, "disabled per chip default"); + return false; + } + + if (!i915.enable_fbc) { + set_no_fbc_reason(dev_priv, "disabled per module param"); + return false; + } + + if (!crtc_can_fbc(crtc)) { + set_no_fbc_reason(dev_priv, "no enabled pipes can have FBC"); + return false; + } + + return true; +} + /** * __intel_fbc_update - activate/deactivate FBC as needed, unlocked * @crtc: the CRTC that triggered the update @@ -997,25 +1024,8 @@ void intel_fbc_enable(struct intel_crtc *crtc) WARN_ON(dev_priv->fbc.active); WARN_ON(dev_priv->fbc.crtc != NULL); - if (intel_vgpu_active(dev_priv->dev)) { - set_no_fbc_reason(dev_priv, "VGPU is active"); - goto out; - } - - if (i915.enable_fbc < 0) { - set_no_fbc_reason(dev_priv, "disabled per chip default"); - goto out; - } - - if (!i915.enable_fbc) { - set_no_fbc_reason(dev_priv, "disabled per module param"); + if (!intel_fbc_can_enable(crtc)) goto out; - } - - if (!crtc_can_fbc(crtc)) { - set_no_fbc_reason(dev_priv, "no enabled pipes can have FBC"); - goto out; - } if (intel_fbc_alloc_cfb(crtc)) { set_no_fbc_reason(dev_priv, "not enough stolen memory"); -- cgit v0.10.2 From b183b3f143959b8eea5d0970fd4ffe78df3a0210 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 23 Dec 2015 18:28:11 -0200 Subject: drm/i915/fbc: introduce struct intel_fbc_reg_params The early return inside __intel_fbc_update does not completely check all the parameters that affect the FBC register values. For example, we currently lack looking at crtc->adjusted_y (for the fence Y offset) and all the parameters that affect the CFB size (for i8xx). Instead of just adding the missing parameters to the check and hoping that any changes to the fbc_activate functions also come with a matching change to the __intel_fbc_update check, introduce a new structure where we store these parameters and use the structure at the fbc_activate function. Of course, it's still possible to access everything from dev_priv in those functions, but IMHO the new code will be harder to break. v2: Rebase. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-5-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 83b629b..99bac7e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -905,11 +905,9 @@ struct i915_fbc { * it's the outer lock when overlapping with stolen_lock. */ struct mutex lock; unsigned threshold; - unsigned int fb_id; unsigned int possible_framebuffer_bits; unsigned int busy_bits; struct intel_crtc *crtc; - int y; struct drm_mm_node compressed_fb; struct drm_mm_node *compressed_llb; @@ -919,6 +917,24 @@ struct i915_fbc { bool enabled; bool active; + struct intel_fbc_reg_params { + struct { + enum pipe pipe; + enum plane plane; + unsigned int fence_y_offset; + } crtc; + + struct { + u64 ggtt_offset; + uint32_t id; + uint32_t pixel_format; + unsigned int stride; + int fence_reg; + } fb; + + int cfb_size; + } params; + struct intel_fbc_work { bool scheduled; u32 scheduled_vblank; @@ -929,7 +945,7 @@ struct i915_fbc { const char *no_fbc_reason; bool (*is_active)(struct drm_i915_private *dev_priv); - void (*activate)(struct intel_crtc *crtc); + void (*activate)(struct drm_i915_private *dev_priv); void (*deactivate)(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 f76b158..14200d2 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -130,11 +130,9 @@ static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv) } } -static void i8xx_fbc_activate(struct intel_crtc *crtc) +static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct drm_framebuffer *fb = crtc->base.primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_fbc_reg_params *params = &dev_priv->fbc.params; int cfb_pitch; int i; u32 fbc_ctl; @@ -142,9 +140,9 @@ static void i8xx_fbc_activate(struct intel_crtc *crtc) dev_priv->fbc.active = true; /* Note: fbc.threshold == 1 for i8xx */ - cfb_pitch = intel_fbc_calculate_cfb_size(crtc, fb) / FBC_LL_SIZE; - if (fb->pitches[0] < cfb_pitch) - cfb_pitch = fb->pitches[0]; + cfb_pitch = params->cfb_size / FBC_LL_SIZE; + if (params->fb.stride < cfb_pitch) + cfb_pitch = params->fb.stride; /* FBC_CTL wants 32B or 64B units */ if (IS_GEN2(dev_priv)) @@ -161,9 +159,9 @@ static void i8xx_fbc_activate(struct intel_crtc *crtc) /* Set it up... */ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= FBC_CTL_PLANE(crtc->plane); + fbc_ctl2 |= FBC_CTL_PLANE(params->crtc.plane); I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, get_crtc_fence_y_offset(crtc)); + I915_WRITE(FBC_FENCE_OFF, params->crtc.fence_y_offset); } /* enable it... */ @@ -173,7 +171,7 @@ static void i8xx_fbc_activate(struct intel_crtc *crtc) if (IS_I945GM(dev_priv)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= obj->fence_reg; + fbc_ctl |= params->fb.fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); } @@ -182,23 +180,21 @@ static bool i8xx_fbc_is_active(struct drm_i915_private *dev_priv) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_fbc_activate(struct intel_crtc *crtc) +static void g4x_fbc_activate(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct drm_framebuffer *fb = crtc->base.primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_fbc_reg_params *params = &dev_priv->fbc.params; u32 dpfc_ctl; dev_priv->fbc.active = true; - dpfc_ctl = DPFC_CTL_PLANE(crtc->plane) | DPFC_SR_EN; - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl = DPFC_CTL_PLANE(params->crtc.plane) | DPFC_SR_EN; + if (drm_format_plane_cpp(params->fb.pixel_format, 0) == 2) dpfc_ctl |= DPFC_CTL_LIMIT_2X; else dpfc_ctl |= DPFC_CTL_LIMIT_1X; - dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; + dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg; - I915_WRITE(DPFC_FENCE_YOFF, get_crtc_fence_y_offset(crtc)); + I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset); /* enable it... */ I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -230,19 +226,16 @@ static void intel_fbc_recompress(struct drm_i915_private *dev_priv) POSTING_READ(MSG_FBC_REND_STATE); } -static void ilk_fbc_activate(struct intel_crtc *crtc) +static void ilk_fbc_activate(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct drm_framebuffer *fb = crtc->base.primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_fbc_reg_params *params = &dev_priv->fbc.params; u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; - unsigned int y_offset; dev_priv->fbc.active = true; - dpfc_ctl = DPFC_CTL_PLANE(crtc->plane); - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + dpfc_ctl = DPFC_CTL_PLANE(params->crtc.plane); + if (drm_format_plane_cpp(params->fb.pixel_format, 0) == 2) threshold++; switch (threshold) { @@ -259,18 +252,17 @@ static void ilk_fbc_activate(struct intel_crtc *crtc) } dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev_priv)) - dpfc_ctl |= obj->fence_reg; + dpfc_ctl |= params->fb.fence_reg; - y_offset = get_crtc_fence_y_offset(crtc); - I915_WRITE(ILK_DPFC_FENCE_YOFF, y_offset); - I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); + I915_WRITE(ILK_DPFC_FENCE_YOFF, params->crtc.fence_y_offset); + I915_WRITE(ILK_FBC_RT_BASE, params->fb.ggtt_offset | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, y_offset); + SNB_CPU_FENCE_ENABLE | params->fb.fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset); } intel_fbc_recompress(dev_priv); @@ -295,11 +287,9 @@ static bool ilk_fbc_is_active(struct drm_i915_private *dev_priv) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_fbc_activate(struct intel_crtc *crtc) +static void gen7_fbc_activate(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct drm_framebuffer *fb = crtc->base.primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_fbc_reg_params *params = &dev_priv->fbc.params; u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; @@ -307,9 +297,9 @@ static void gen7_fbc_activate(struct intel_crtc *crtc) dpfc_ctl = 0; if (IS_IVYBRIDGE(dev_priv)) - dpfc_ctl |= IVB_DPFC_CTL_PLANE(crtc->plane); + dpfc_ctl |= IVB_DPFC_CTL_PLANE(params->crtc.plane); - if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) + if (drm_format_plane_cpp(params->fb.pixel_format, 0) == 2) threshold++; switch (threshold) { @@ -337,16 +327,16 @@ static void gen7_fbc_activate(struct intel_crtc *crtc) ILK_FBCQ_DIS); } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - I915_WRITE(CHICKEN_PIPESL_1(crtc->pipe), - I915_READ(CHICKEN_PIPESL_1(crtc->pipe)) | + I915_WRITE(CHICKEN_PIPESL_1(params->crtc.pipe), + I915_READ(CHICKEN_PIPESL_1(params->crtc.pipe)) | HSW_FBCQ_DIS); } I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, get_crtc_fence_y_offset(crtc)); + SNB_CPU_FENCE_ENABLE | params->fb.fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset); intel_fbc_recompress(dev_priv); } @@ -364,17 +354,6 @@ bool intel_fbc_is_active(struct drm_i915_private *dev_priv) return dev_priv->fbc.active; } -static void intel_fbc_activate(const struct drm_framebuffer *fb) -{ - struct drm_i915_private *dev_priv = fb->dev->dev_private; - struct intel_crtc *crtc = dev_priv->fbc.crtc; - - dev_priv->fbc.activate(crtc); - - dev_priv->fbc.fb_id = fb->base.id; - dev_priv->fbc.y = crtc->base.y; -} - static void intel_fbc_work_fn(struct work_struct *__work) { struct drm_i915_private *dev_priv = @@ -424,7 +403,7 @@ retry: } if (crtc->base.primary->fb == work->fb) - intel_fbc_activate(work->fb); + dev_priv->fbc.activate(dev_priv); work->scheduled = false; @@ -855,6 +834,42 @@ static bool intel_fbc_can_enable(struct intel_crtc *crtc) return true; } +static void intel_fbc_get_reg_params(struct intel_crtc *crtc, + struct intel_fbc_reg_params *params) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + + /* Since all our fields are integer types, use memset here so the + * comparison function can rely on memcmp because the padding will be + * zero. */ + memset(params, 0, sizeof(*params)); + + params->crtc.pipe = crtc->pipe; + params->crtc.plane = crtc->plane; + params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc); + + params->fb.id = fb->base.id; + params->fb.pixel_format = fb->pixel_format; + params->fb.stride = fb->pitches[0]; + params->fb.fence_reg = obj->fence_reg; + + params->cfb_size = intel_fbc_calculate_cfb_size(crtc, fb); + + /* FIXME: We lack the proper locking here, so only run this on the + * platforms that need. */ + if (dev_priv->fbc.activate == ilk_fbc_activate) + params->fb.ggtt_offset = i915_gem_obj_ggtt_offset(obj); +} + +static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, + struct intel_fbc_reg_params *params2) +{ + /* We can use this since intel_fbc_get_reg_params() does a memset. */ + return memcmp(params1, params2, sizeof(*params1)) == 0; +} + /** * __intel_fbc_update - activate/deactivate FBC as needed, unlocked * @crtc: the CRTC that triggered the update @@ -865,6 +880,7 @@ static bool intel_fbc_can_enable(struct intel_crtc *crtc) static void __intel_fbc_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc_reg_params old_params; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -879,15 +895,16 @@ static void __intel_fbc_update(struct intel_crtc *crtc) if (!intel_fbc_can_activate(crtc)) goto out_disable; + old_params = dev_priv->fbc.params; + intel_fbc_get_reg_params(crtc, &dev_priv->fbc.params); + /* If the scanout has not changed, don't modify the FBC settings. * Note that we make the fundamental assumption that the fb->obj * cannot be unpinned (and have its GTT offset and fence revoked) * without first being decoupled from the scanout and FBC disabled. */ - if (dev_priv->fbc.crtc == crtc && - dev_priv->fbc.fb_id == crtc->base.primary->fb->base.id && - dev_priv->fbc.y == crtc->base.y && - dev_priv->fbc.active) + if (dev_priv->fbc.active && + intel_fbc_reg_params_equal(&old_params, &dev_priv->fbc.params)) return; if (intel_fbc_is_active(dev_priv)) { -- cgit v0.10.2 From ab34a7e8b55a1cbe3f0ad1bb2d7d24568ce4d018 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 11 Jan 2016 17:44:36 -0200 Subject: drm/i915/fbc: replace frequent dev_priv->fbc.x with fbc->x We say "dev_priv->fbc.something" way too many times in our code while we could be saying just "fbc->something" with a previous declaration of fbc. This has been bothering me for a while but I didn't want to patch it since I wanted to fix the real problems first. But as I add more code I keep thinking about it, especially since it makes the code easier to read and it can make us fit 80 columns easier, so let's just do the change now. While at it, also rename from i915_fbc to intel_fbc because the whole FBC code uses intel_fbc. v2: Rebase after the work_fn changes. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453406763-10400-1-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 99bac7e..7b44e98 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -900,7 +900,7 @@ enum fb_op_origin { ORIGIN_DIRTYFB, }; -struct i915_fbc { +struct intel_fbc { /* This is always the inner lock when overlapping with struct_mutex and * it's the outer lock when overlapping with stolen_lock. */ struct mutex lock; @@ -1781,7 +1781,7 @@ struct drm_i915_private { u32 pipestat_irq_mask[I915_MAX_PIPES]; struct i915_hotplug hotplug; - struct i915_fbc fbc; + struct intel_fbc fbc; struct i915_drrs drrs; struct intel_opregion opregion; struct intel_vbt_data vbt; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 14200d2..a0bdcef 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -358,17 +358,18 @@ static void intel_fbc_work_fn(struct work_struct *__work) { struct drm_i915_private *dev_priv = container_of(__work, struct drm_i915_private, fbc.work.work); - struct intel_fbc_work *work = &dev_priv->fbc.work; - struct intel_crtc *crtc = dev_priv->fbc.crtc; + struct intel_fbc *fbc = &dev_priv->fbc; + struct intel_fbc_work *work = &fbc->work; + struct intel_crtc *crtc = fbc->crtc; struct drm_vblank_crtc *vblank = &dev_priv->dev->vblank[crtc->pipe]; if (drm_crtc_vblank_get(&crtc->base)) { DRM_ERROR("vblank not available for FBC on pipe %c\n", pipe_name(crtc->pipe)); - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); work->scheduled = false; - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); return; } @@ -390,7 +391,7 @@ retry: drm_crtc_vblank_count(&crtc->base) != work->scheduled_vblank, msecs_to_jiffies(50)); - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); /* Were we cancelled? */ if (!work->scheduled) @@ -398,32 +399,35 @@ retry: /* Were we delayed again while this function was sleeping? */ if (drm_crtc_vblank_count(&crtc->base) == work->scheduled_vblank) { - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); goto retry; } if (crtc->base.primary->fb == work->fb) - dev_priv->fbc.activate(dev_priv); + fbc->activate(dev_priv); work->scheduled = false; out: - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); drm_crtc_vblank_put(&crtc->base); } static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) { - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - dev_priv->fbc.work.scheduled = false; + struct intel_fbc *fbc = &dev_priv->fbc; + + WARN_ON(!mutex_is_locked(&fbc->lock)); + fbc->work.scheduled = false; } static void intel_fbc_schedule_activation(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct intel_fbc_work *work = &dev_priv->fbc.work; + struct intel_fbc *fbc = &dev_priv->fbc; + struct intel_fbc_work *work = &fbc->work; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + WARN_ON(!mutex_is_locked(&fbc->lock)); if (drm_crtc_vblank_get(&crtc->base)) { DRM_ERROR("vblank not available for FBC on pipe %c\n", @@ -445,12 +449,14 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv) { - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + struct intel_fbc *fbc = &dev_priv->fbc; + + WARN_ON(!mutex_is_locked(&fbc->lock)); intel_fbc_cancel_work(dev_priv); - if (dev_priv->fbc.active) - dev_priv->fbc.deactivate(dev_priv); + if (fbc->active) + fbc->deactivate(dev_priv); } /* @@ -462,23 +468,26 @@ static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv) void intel_fbc_deactivate(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); - if (dev_priv->fbc.crtc == crtc) + mutex_lock(&fbc->lock); + if (fbc->crtc == crtc) __intel_fbc_deactivate(dev_priv); - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } static void set_no_fbc_reason(struct drm_i915_private *dev_priv, const char *reason) { - if (dev_priv->fbc.no_fbc_reason == reason) + struct intel_fbc *fbc = &dev_priv->fbc; + + if (fbc->no_fbc_reason == reason) return; - dev_priv->fbc.no_fbc_reason = reason; + fbc->no_fbc_reason = reason; DRM_DEBUG_KMS("Disabling FBC: %s\n", reason); } @@ -568,16 +577,17 @@ again: static int intel_fbc_alloc_cfb(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; struct drm_framebuffer *fb = crtc->base.primary->state->fb; struct drm_mm_node *uninitialized_var(compressed_llb); int size, fb_cpp, ret; - WARN_ON(drm_mm_node_allocated(&dev_priv->fbc.compressed_fb)); + WARN_ON(drm_mm_node_allocated(&fbc->compressed_fb)); size = intel_fbc_calculate_cfb_size(crtc, fb); fb_cpp = drm_format_plane_cpp(fb->pixel_format, 0); - ret = find_compression_threshold(dev_priv, &dev_priv->fbc.compressed_fb, + ret = find_compression_threshold(dev_priv, &fbc->compressed_fb, size, fb_cpp); if (!ret) goto err_llb; @@ -586,12 +596,12 @@ static int intel_fbc_alloc_cfb(struct intel_crtc *crtc) } - dev_priv->fbc.threshold = ret; + fbc->threshold = ret; if (INTEL_INFO(dev_priv)->gen >= 5) - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + I915_WRITE(ILK_DPFC_CB_BASE, fbc->compressed_fb.start); else if (IS_GM45(dev_priv)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + I915_WRITE(DPFC_CB_BASE, fbc->compressed_fb.start); } else { compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); if (!compressed_llb) @@ -602,23 +612,22 @@ static int intel_fbc_alloc_cfb(struct intel_crtc *crtc) if (ret) goto err_fb; - dev_priv->fbc.compressed_llb = compressed_llb; + fbc->compressed_llb = compressed_llb; I915_WRITE(FBC_CFB_BASE, - dev_priv->mm.stolen_base + dev_priv->fbc.compressed_fb.start); + dev_priv->mm.stolen_base + fbc->compressed_fb.start); I915_WRITE(FBC_LL_BASE, dev_priv->mm.stolen_base + compressed_llb->start); } DRM_DEBUG_KMS("reserved %llu bytes of contiguous stolen space for FBC, threshold: %d\n", - dev_priv->fbc.compressed_fb.size, - dev_priv->fbc.threshold); + fbc->compressed_fb.size, fbc->threshold); return 0; err_fb: kfree(compressed_llb); - i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); + i915_gem_stolen_remove_node(dev_priv, &fbc->compressed_fb); err_llb: pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); return -ENOSPC; @@ -626,25 +635,27 @@ err_llb: static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - if (drm_mm_node_allocated(&dev_priv->fbc.compressed_fb)) - i915_gem_stolen_remove_node(dev_priv, - &dev_priv->fbc.compressed_fb); - - if (dev_priv->fbc.compressed_llb) { - i915_gem_stolen_remove_node(dev_priv, - dev_priv->fbc.compressed_llb); - kfree(dev_priv->fbc.compressed_llb); + struct intel_fbc *fbc = &dev_priv->fbc; + + if (drm_mm_node_allocated(&fbc->compressed_fb)) + i915_gem_stolen_remove_node(dev_priv, &fbc->compressed_fb); + + if (fbc->compressed_llb) { + i915_gem_stolen_remove_node(dev_priv, fbc->compressed_llb); + kfree(fbc->compressed_llb); } } void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { + struct intel_fbc *fbc = &dev_priv->fbc; + if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); __intel_fbc_cleanup_cfb(dev_priv); - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } static bool stride_is_valid(struct drm_i915_private *dev_priv, @@ -723,6 +734,7 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) static bool intel_fbc_can_activate(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; struct drm_plane *primary; struct drm_framebuffer *fb; struct intel_plane_state *plane_state; @@ -799,7 +811,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) * a lot of tracking just for a specific case. If we conclude it's an * important case, we can implement it later. */ if (intel_fbc_calculate_cfb_size(crtc, fb) > - dev_priv->fbc.compressed_fb.size * dev_priv->fbc.threshold) { + fbc->compressed_fb.size * fbc->threshold) { set_no_fbc_reason(dev_priv, "CFB requirements changed"); return false; } @@ -880,31 +892,32 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, static void __intel_fbc_update(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_reg_params old_params; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + WARN_ON(!mutex_is_locked(&fbc->lock)); if (!multiple_pipes_ok(dev_priv)) { set_no_fbc_reason(dev_priv, "more than one pipe active"); goto out_disable; } - if (!dev_priv->fbc.enabled || dev_priv->fbc.crtc != crtc) + if (!fbc->enabled || fbc->crtc != crtc) return; if (!intel_fbc_can_activate(crtc)) goto out_disable; - old_params = dev_priv->fbc.params; - intel_fbc_get_reg_params(crtc, &dev_priv->fbc.params); + old_params = fbc->params; + intel_fbc_get_reg_params(crtc, &fbc->params); /* If the scanout has not changed, don't modify the FBC settings. * Note that we make the fundamental assumption that the fb->obj * cannot be unpinned (and have its GTT offset and fence revoked) * without first being decoupled from the scanout and FBC disabled. */ - if (dev_priv->fbc.active && - intel_fbc_reg_params_equal(&old_params, &dev_priv->fbc.params)) + if (fbc->active && + intel_fbc_reg_params_equal(&old_params, &fbc->params)) return; if (intel_fbc_is_active(dev_priv)) { @@ -936,7 +949,7 @@ static void __intel_fbc_update(struct intel_crtc *crtc) } intel_fbc_schedule_activation(crtc); - dev_priv->fbc.no_fbc_reason = "FBC enabled (not necessarily active)"; + fbc->no_fbc_reason = "FBC enabled (not necessarily active)"; return; out_disable: @@ -956,19 +969,21 @@ out_disable: void intel_fbc_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); __intel_fbc_update(crtc); - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { + struct intel_fbc *fbc = &dev_priv->fbc; unsigned int fbc_bits; if (!fbc_supported(dev_priv)) @@ -977,44 +992,46 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, if (origin == ORIGIN_GTT) return; - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); - if (dev_priv->fbc.enabled) - fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe); + if (fbc->enabled) + fbc_bits = INTEL_FRONTBUFFER_PRIMARY(fbc->crtc->pipe); else - fbc_bits = dev_priv->fbc.possible_framebuffer_bits; + fbc_bits = fbc->possible_framebuffer_bits; - dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits); + fbc->busy_bits |= (fbc_bits & frontbuffer_bits); - if (dev_priv->fbc.busy_bits) + if (fbc->busy_bits) __intel_fbc_deactivate(dev_priv); - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { + struct intel_fbc *fbc = &dev_priv->fbc; + if (!fbc_supported(dev_priv)) return; if (origin == ORIGIN_GTT) return; - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); - dev_priv->fbc.busy_bits &= ~frontbuffer_bits; + fbc->busy_bits &= ~frontbuffer_bits; - if (!dev_priv->fbc.busy_bits && dev_priv->fbc.enabled) { - if (origin != ORIGIN_FLIP && dev_priv->fbc.active) { + if (!fbc->busy_bits && fbc->enabled) { + if (origin != ORIGIN_FLIP && fbc->active) { intel_fbc_recompress(dev_priv); } else { __intel_fbc_deactivate(dev_priv); - __intel_fbc_update(dev_priv->fbc.crtc); + __intel_fbc_update(fbc->crtc); } } - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } /** @@ -1027,19 +1044,20 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, 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; if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); + mutex_lock(&fbc->lock); - if (dev_priv->fbc.enabled) { - WARN_ON(dev_priv->fbc.crtc == crtc); + if (fbc->enabled) { + WARN_ON(fbc->crtc == crtc); goto out; } - WARN_ON(dev_priv->fbc.active); - WARN_ON(dev_priv->fbc.crtc != NULL); + WARN_ON(fbc->active); + WARN_ON(fbc->crtc != NULL); if (!intel_fbc_can_enable(crtc)) goto out; @@ -1050,12 +1068,12 @@ void intel_fbc_enable(struct intel_crtc *crtc) } DRM_DEBUG_KMS("Enabling FBC on pipe %c\n", pipe_name(crtc->pipe)); - dev_priv->fbc.no_fbc_reason = "FBC enabled but not active yet\n"; + fbc->no_fbc_reason = "FBC enabled but not active yet\n"; - dev_priv->fbc.enabled = true; - dev_priv->fbc.crtc = crtc; + fbc->enabled = true; + fbc->crtc = crtc; out: - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } /** @@ -1067,19 +1085,20 @@ out: */ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) { - struct intel_crtc *crtc = dev_priv->fbc.crtc; + struct intel_fbc *fbc = &dev_priv->fbc; + struct intel_crtc *crtc = fbc->crtc; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - WARN_ON(!dev_priv->fbc.enabled); - WARN_ON(dev_priv->fbc.active); + WARN_ON(!mutex_is_locked(&fbc->lock)); + WARN_ON(!fbc->enabled); + WARN_ON(fbc->active); assert_pipe_disabled(dev_priv, crtc->pipe); DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe)); __intel_fbc_cleanup_cfb(dev_priv); - dev_priv->fbc.enabled = false; - dev_priv->fbc.crtc = NULL; + fbc->enabled = false; + fbc->crtc = NULL; } /** @@ -1091,17 +1110,18 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) void intel_fbc_disable_crtc(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); - if (dev_priv->fbc.crtc == crtc) { - WARN_ON(!dev_priv->fbc.enabled); - WARN_ON(dev_priv->fbc.active); + mutex_lock(&fbc->lock); + if (fbc->crtc == crtc) { + WARN_ON(!fbc->enabled); + WARN_ON(fbc->active); __intel_fbc_disable(dev_priv); } - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } /** @@ -1112,13 +1132,15 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) */ void intel_fbc_disable(struct drm_i915_private *dev_priv) { + struct intel_fbc *fbc = &dev_priv->fbc; + if (!fbc_supported(dev_priv)) return; - mutex_lock(&dev_priv->fbc.lock); - if (dev_priv->fbc.enabled) + mutex_lock(&fbc->lock); + if (fbc->enabled) __intel_fbc_disable(dev_priv); - mutex_unlock(&dev_priv->fbc.lock); + mutex_unlock(&fbc->lock); } /** @@ -1129,21 +1151,22 @@ void intel_fbc_disable(struct drm_i915_private *dev_priv) */ void intel_fbc_init(struct drm_i915_private *dev_priv) { + struct intel_fbc *fbc = &dev_priv->fbc; enum pipe pipe; - INIT_WORK(&dev_priv->fbc.work.work, intel_fbc_work_fn); - mutex_init(&dev_priv->fbc.lock); - dev_priv->fbc.enabled = false; - dev_priv->fbc.active = false; - dev_priv->fbc.work.scheduled = false; + INIT_WORK(&fbc->work.work, intel_fbc_work_fn); + mutex_init(&fbc->lock); + fbc->enabled = false; + fbc->active = false; + fbc->work.scheduled = false; if (!HAS_FBC(dev_priv)) { - dev_priv->fbc.no_fbc_reason = "unsupported by this chipset"; + fbc->no_fbc_reason = "unsupported by this chipset"; return; } for_each_pipe(dev_priv, pipe) { - dev_priv->fbc.possible_framebuffer_bits |= + fbc->possible_framebuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(pipe); if (fbc_on_pipe_a_only(dev_priv)) @@ -1151,21 +1174,21 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) } if (INTEL_INFO(dev_priv)->gen >= 7) { - dev_priv->fbc.is_active = ilk_fbc_is_active; - dev_priv->fbc.activate = gen7_fbc_activate; - dev_priv->fbc.deactivate = ilk_fbc_deactivate; + fbc->is_active = ilk_fbc_is_active; + fbc->activate = gen7_fbc_activate; + fbc->deactivate = ilk_fbc_deactivate; } else if (INTEL_INFO(dev_priv)->gen >= 5) { - dev_priv->fbc.is_active = ilk_fbc_is_active; - dev_priv->fbc.activate = ilk_fbc_activate; - dev_priv->fbc.deactivate = ilk_fbc_deactivate; + fbc->is_active = ilk_fbc_is_active; + fbc->activate = ilk_fbc_activate; + fbc->deactivate = ilk_fbc_deactivate; } else if (IS_GM45(dev_priv)) { - dev_priv->fbc.is_active = g4x_fbc_is_active; - dev_priv->fbc.activate = g4x_fbc_activate; - dev_priv->fbc.deactivate = g4x_fbc_deactivate; + fbc->is_active = g4x_fbc_is_active; + fbc->activate = g4x_fbc_activate; + fbc->deactivate = g4x_fbc_deactivate; } else { - dev_priv->fbc.is_active = i8xx_fbc_is_active; - dev_priv->fbc.activate = i8xx_fbc_activate; - dev_priv->fbc.deactivate = i8xx_fbc_deactivate; + fbc->is_active = i8xx_fbc_is_active; + fbc->activate = i8xx_fbc_activate; + fbc->deactivate = i8xx_fbc_deactivate; /* This value was pulled out of someone's hat */ I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); @@ -1174,6 +1197,6 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) /* We still don't have any sort of hardware state readout for FBC, so * deactivate it in case the BIOS activated it to make sure software * matches the hardware state. */ - if (dev_priv->fbc.is_active(dev_priv)) - dev_priv->fbc.deactivate(dev_priv); + if (fbc->is_active(dev_priv)) + fbc->deactivate(dev_priv); } -- cgit v0.10.2 From 0dd81544c9dd1ba867e7cd2e18d719437b3c97c1 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:39 -0200 Subject: drm/i915/fbc: don't use the frontbuffer tracking subsystem for flips Before this patch, page flips would call intel_frontbuffer_flip() and intel_frontbuffer_flip_complete(), which would call intel_fbc_flush(), which would call intel_fbc_update(). The problem is that drawing operations also trigger intel_fbc_flush() calls, so it's not guaranteed that we have the CRTC and FB locks grabbed when intel_fbc_flush() happens, since the call trace may come from the rendering path. We're trying to make the FBC code grab the appropriate CRTC/FB locks, so split the drawing and the flipping logic in order to achieve that in later patches. So now the frontbuffer tracking code is just going to be used for frontbuffer drawing, and intel_fbc_update() is going to be used directly for actual page flips. As a note, we don't need to call intel_fbc_flip() during the two places where we call intel_frontbuffer_flip() since in one of them we already have an intel_fbc_update() call, and in the other we have the planes disabled. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-7-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 304fc96..d56b934 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10912,6 +10912,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit); + intel_fbc_update(crtc); drm_framebuffer_unreference(work->old_fb); BUG_ON(atomic_read(&crtc->unpin_work_count) == 0); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a0bdcef..8c765f6 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -989,7 +989,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, if (!fbc_supported(dev_priv)) return; - if (origin == ORIGIN_GTT) + if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP) return; mutex_lock(&fbc->lock); @@ -1015,7 +1015,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, if (!fbc_supported(dev_priv)) return; - if (origin == ORIGIN_GTT) + if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP) return; mutex_lock(&fbc->lock); @@ -1023,12 +1023,10 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, fbc->busy_bits &= ~frontbuffer_bits; if (!fbc->busy_bits && fbc->enabled) { - if (origin != ORIGIN_FLIP && fbc->active) { + if (fbc->active) intel_fbc_recompress(dev_priv); - } else { - __intel_fbc_deactivate(dev_priv); + else __intel_fbc_update(fbc->crtc); - } } mutex_unlock(&fbc->lock); -- cgit v0.10.2 From 261fe99ac26bde82f44163b0d7f67b9ccf562359 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:40 -0200 Subject: drm/i915/fbc: don't flush for operations on the wrong frontbuffer If frontbuffer_bits doesn't match the current frontbuffer, there's no reason to recompress or update FBC. There was a plan to make the FBC test suite catch this type of problem, but it never got implemented due to being low priority. While at it, also implement Ville's suggestion and use plane->frontbuffer_bit instead of INTEL_FRONTBUFFER_PRIMARY. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-8-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 8c765f6..a24cb8d 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -979,12 +979,19 @@ void intel_fbc_update(struct intel_crtc *crtc) mutex_unlock(&fbc->lock); } +static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc) +{ + if (fbc->enabled) + return to_intel_plane(fbc->crtc->base.primary)->frontbuffer_bit; + else + return fbc->possible_framebuffer_bits; +} + void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { struct intel_fbc *fbc = &dev_priv->fbc; - unsigned int fbc_bits; if (!fbc_supported(dev_priv)) return; @@ -994,12 +1001,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, mutex_lock(&fbc->lock); - if (fbc->enabled) - fbc_bits = INTEL_FRONTBUFFER_PRIMARY(fbc->crtc->pipe); - else - fbc_bits = fbc->possible_framebuffer_bits; - - fbc->busy_bits |= (fbc_bits & frontbuffer_bits); + fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; if (fbc->busy_bits) __intel_fbc_deactivate(dev_priv); @@ -1022,7 +1024,8 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, fbc->busy_bits &= ~frontbuffer_bits; - if (!fbc->busy_bits && fbc->enabled) { + if (!fbc->busy_bits && fbc->enabled && + (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) { if (fbc->active) intel_fbc_recompress(dev_priv); else -- cgit v0.10.2 From fcf38d134983c1dbc3f426f6e562d93514fde1f1 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 21 Jan 2016 18:07:17 -0200 Subject: drm/i915/fbc: unconditionally update FBC during atomic commits We unconditionally disable/update FBC even during the page flip IOCTLs, and an unconditional disable/update at every atomic commit touching the primary plane shouldn't impact PC state residency noticeably. Besides, the code that checks for rotation is a good hint that we may be forgetting something else, so let's leave all the decisions to intel_fbc.c, making the code much safer. Once we have the code to properly make FBC enable/update decisions based on atomic states, with proper locking, then we'll be able to evaluate whether it will be worth trying to optimize the cases where a disable isn't needed. v2: Upstream moved and now our patch needs to remove dev_priv. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453406837-10511-1-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d56b934..25af606 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11834,7 +11834,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_plane *plane = plane_state->plane; struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane_state *old_plane_state = to_intel_plane_state(plane->state); int idx = intel_crtc->base.base.id, ret; @@ -11902,6 +11901,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, case DRM_PLANE_TYPE_PRIMARY: intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; + intel_crtc->atomic.disable_fbc = true; + intel_crtc->atomic.update_fbc = true; if (turn_off) { /* @@ -11913,28 +11914,9 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, * disable. */ intel_crtc->atomic.disable_ips = true; - - intel_crtc->atomic.disable_fbc = true; } /* - * FBC does not work on some platforms for rotated - * planes, so disable it when rotation is not 0 and - * update it when rotation is set back to 0. - * - * FIXME: This is redundant with the fbc update done in - * the primary plane enable function except that that - * one is done too late. We eventually need to unify - * this. - */ - - if (visible && - INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - dev_priv->fbc.crtc == intel_crtc && - plane_state->rotation != BIT(DRM_ROTATE_0)) - intel_crtc->atomic.disable_fbc = true; - - /* * BDW signals flip done immediately if the plane * is disabled, even if the plane enable is already * armed to occur at the next vblank :( @@ -11942,7 +11924,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, if (turn_on && IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; - intel_crtc->atomic.update_fbc |= visible || mode_changed; break; case DRM_PLANE_TYPE_CURSOR: break; -- cgit v0.10.2 From aaf78d276ba00ad0ab9e51283b3e3e8db8433ead Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:42 -0200 Subject: drm/i915/fbc: introduce struct intel_fbc_state_cache Per the new atomic locking rules, we need to cache the CRTC, plane and FB state structures we use so we can access them later without needing more locks. So do this. Notice that there are some pieces of the FBC code that look at things that are only computed during the modeset, so we can't just can't precompute whether FBC can be activated during the update_state_cache stage. We may be able to do this later. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-10-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b44e98..0df9913 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -917,6 +917,29 @@ struct intel_fbc { bool enabled; bool active; + struct intel_fbc_state_cache { + struct { + unsigned int mode_flags; + uint32_t hsw_bdw_pixel_rate; + } crtc; + + struct { + unsigned int rotation; + int src_w; + int src_h; + bool visible; + } plane; + + struct { + u64 ilk_ggtt_offset; + uint32_t id; + uint32_t pixel_format; + unsigned int stride; + int fence_reg; + unsigned int tiling_mode; + } fb; + } state_cache; + struct intel_fbc_reg_params { struct { enum pipe pipe; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a24cb8d..49d445a 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -74,19 +74,17 @@ static unsigned int get_crtc_fence_y_offset(struct intel_crtc *crtc) * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value * we wrote to PIPESRC. */ -static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc, +static void intel_fbc_get_plane_source_size(struct intel_fbc_state_cache *cache, int *width, int *height) { - struct intel_plane_state *plane_state = - to_intel_plane_state(crtc->base.primary->state); int w, h; - if (intel_rotation_90_or_270(plane_state->base.rotation)) { - w = drm_rect_height(&plane_state->src) >> 16; - h = drm_rect_width(&plane_state->src) >> 16; + if (intel_rotation_90_or_270(cache->plane.rotation)) { + w = cache->plane.src_h; + h = cache->plane.src_w; } else { - w = drm_rect_width(&plane_state->src) >> 16; - h = drm_rect_height(&plane_state->src) >> 16; + w = cache->plane.src_w; + h = cache->plane.src_h; } if (width) @@ -95,18 +93,17 @@ static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc, *height = h; } -static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc, - struct drm_framebuffer *fb) +static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv, + struct intel_fbc_state_cache *cache) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; int lines; - intel_fbc_get_plane_source_size(crtc, NULL, &lines); + intel_fbc_get_plane_source_size(cache, NULL, &lines); if (INTEL_INFO(dev_priv)->gen >= 7) lines = min(lines, 2048); /* Hardware needs the full buffer stride, not just the active area. */ - return lines * fb->pitches[0]; + return lines * cache->fb.stride; } static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv) @@ -578,14 +575,13 @@ static int intel_fbc_alloc_cfb(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; - struct drm_framebuffer *fb = crtc->base.primary->state->fb; struct drm_mm_node *uninitialized_var(compressed_llb); int size, fb_cpp, ret; WARN_ON(drm_mm_node_allocated(&fbc->compressed_fb)); - size = intel_fbc_calculate_cfb_size(crtc, fb); - fb_cpp = drm_format_plane_cpp(fb->pixel_format, 0); + size = intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache); + fb_cpp = drm_format_plane_cpp(fbc->state_cache.fb.pixel_format, 0); ret = find_compression_threshold(dev_priv, &fbc->compressed_fb, size, fb_cpp); @@ -679,19 +675,17 @@ static bool stride_is_valid(struct drm_i915_private *dev_priv, return true; } -static bool pixel_format_is_valid(struct drm_framebuffer *fb) +static bool pixel_format_is_valid(struct drm_i915_private *dev_priv, + uint32_t pixel_format) { - struct drm_device *dev = fb->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - switch (fb->pixel_format) { + switch (pixel_format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: return true; case DRM_FORMAT_XRGB1555: case DRM_FORMAT_RGB565: /* 16bpp not supported on gen2 */ - if (IS_GEN2(dev)) + if (IS_GEN2(dev_priv)) return false; /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(dev_priv)) @@ -711,6 +705,7 @@ static bool pixel_format_is_valid(struct drm_framebuffer *fb) static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; unsigned int effective_w, effective_h, max_w, max_h; if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { @@ -724,41 +719,64 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) max_h = 1536; } - intel_fbc_get_plane_source_size(crtc, &effective_w, &effective_h); + intel_fbc_get_plane_source_size(&fbc->state_cache, &effective_w, + &effective_h); effective_w += crtc->adjusted_x; effective_h += crtc->adjusted_y; return effective_w <= max_w && effective_h <= max_h; } -static bool intel_fbc_can_activate(struct intel_crtc *crtc) +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 drm_plane *primary; - struct drm_framebuffer *fb; - struct intel_plane_state *plane_state; + struct intel_fbc_state_cache *cache = &fbc->state_cache; + struct intel_crtc_state *crtc_state = crtc->config; + 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; - const struct drm_display_mode *adjusted_mode; - if (!intel_crtc_active(&crtc->base)) { - set_no_fbc_reason(dev_priv, "CRTC not active"); - return false; - } + 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 = + ilk_pipe_pixel_rate(crtc_state); + + cache->plane.rotation = plane_state->base.rotation; + cache->plane.src_w = drm_rect_width(&plane_state->src) >> 16; + cache->plane.src_h = drm_rect_height(&plane_state->src) >> 16; + cache->plane.visible = plane_state->visible; + + if (!cache->plane.visible) + return; - primary = crtc->base.primary; - fb = primary->fb; obj = intel_fb_obj(fb); - adjusted_mode = &crtc->config->base.adjusted_mode; - plane_state = to_intel_plane_state(primary->state); - if (!plane_state->visible) { + /* FIXME: We lack the proper locking here, so only run this on the + * platforms that need. */ + if (dev_priv->fbc.activate == ilk_fbc_activate) + cache->fb.ilk_ggtt_offset = i915_gem_obj_ggtt_offset(obj); + cache->fb.id = fb->base.id; + cache->fb.pixel_format = fb->pixel_format; + cache->fb.stride = fb->pitches[0]; + cache->fb.fence_reg = obj->fence_reg; + cache->fb.tiling_mode = obj->tiling_mode; +} + +static bool intel_fbc_can_activate(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; + + if (!cache->plane.visible) { set_no_fbc_reason(dev_priv, "primary plane not visible"); return false; } - if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || - (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { + if ((cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) || + (cache->crtc.mode_flags & DRM_MODE_FLAG_DBLSCAN)) { set_no_fbc_reason(dev_priv, "incompatible mode"); return false; } @@ -771,31 +789,30 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) /* The use of a CPU fence is mandatory in order to detect writes * by the CPU to the scanout and trigger updates to the FBC. */ - if (obj->tiling_mode != I915_TILING_X || - obj->fence_reg == I915_FENCE_REG_NONE) { + if (cache->fb.tiling_mode != I915_TILING_X || + cache->fb.fence_reg == I915_FENCE_REG_NONE) { set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced"); return false; } if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && - plane_state->base.rotation != BIT(DRM_ROTATE_0)) { + cache->plane.rotation != BIT(DRM_ROTATE_0)) { set_no_fbc_reason(dev_priv, "rotation unsupported"); return false; } - if (!stride_is_valid(dev_priv, fb->pitches[0])) { + if (!stride_is_valid(dev_priv, cache->fb.stride)) { set_no_fbc_reason(dev_priv, "framebuffer stride not supported"); return false; } - if (!pixel_format_is_valid(fb)) { + if (!pixel_format_is_valid(dev_priv, cache->fb.pixel_format)) { set_no_fbc_reason(dev_priv, "pixel format is invalid"); return false; } /* WaFbcExceedCdClockThreshold:hsw,bdw */ if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) && - ilk_pipe_pixel_rate(crtc->config) >= - dev_priv->cdclk_freq * 95 / 100) { + cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk_freq * 95 / 100) { set_no_fbc_reason(dev_priv, "pixel rate is too big"); return false; } @@ -810,7 +827,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) * we didn't get any invalidate/deactivate calls, but this would require * a lot of tracking just for a specific case. If we conclude it's an * important case, we can implement it later. */ - if (intel_fbc_calculate_cfb_size(crtc, fb) > + if (intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache) > fbc->compressed_fb.size * fbc->threshold) { set_no_fbc_reason(dev_priv, "CFB requirements changed"); return false; @@ -850,8 +867,8 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, struct intel_fbc_reg_params *params) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct drm_framebuffer *fb = crtc->base.primary->fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_fbc *fbc = &dev_priv->fbc; + struct intel_fbc_state_cache *cache = &fbc->state_cache; /* Since all our fields are integer types, use memset here so the * comparison function can rely on memcmp because the padding will be @@ -862,17 +879,14 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, params->crtc.plane = crtc->plane; params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc); - params->fb.id = fb->base.id; - params->fb.pixel_format = fb->pixel_format; - params->fb.stride = fb->pitches[0]; - params->fb.fence_reg = obj->fence_reg; + params->fb.id = cache->fb.id; + params->fb.pixel_format = cache->fb.pixel_format; + params->fb.stride = cache->fb.stride; + params->fb.fence_reg = cache->fb.fence_reg; - params->cfb_size = intel_fbc_calculate_cfb_size(crtc, fb); + params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); - /* FIXME: We lack the proper locking here, so only run this on the - * platforms that need. */ - if (dev_priv->fbc.activate == ilk_fbc_activate) - params->fb.ggtt_offset = i915_gem_obj_ggtt_offset(obj); + params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset; } static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, @@ -905,6 +919,8 @@ static void __intel_fbc_update(struct intel_crtc *crtc) if (!fbc->enabled || fbc->crtc != crtc) return; + intel_fbc_update_state_cache(crtc); + if (!intel_fbc_can_activate(crtc)) goto out_disable; @@ -1063,6 +1079,7 @@ void intel_fbc_enable(struct intel_crtc *crtc) if (!intel_fbc_can_enable(crtc)) goto out; + intel_fbc_update_state_cache(crtc); if (intel_fbc_alloc_cfb(crtc)) { set_no_fbc_reason(dev_priv, "not enough stolen memory"); goto out; -- cgit v0.10.2 From 212890cfcd25b148665585ac3b2ecb65bad0d538 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:43 -0200 Subject: drm/i915/fbc: split intel_fbc_update into pre and post update So now pre_update will be responsible for unconditionally deactivating FBC and updating the state cache, while post_update will be responsible for checking if it can be enabled, then enabling it. This is one more step into proper locking. Notice that intel_fbc_flush now calls post_update directly. The FBC flush can only happen for drawing operations - since we explicitly ignore the flips -, so the FBC state is not expected to have changed at this point. With this we can just run post_update, which will make sure we won't deactivate+reactivate FBC as would be the case now if we called pre_update + post_update. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-11-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 49d445a..61523cd 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -896,24 +896,16 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, return memcmp(params1, params2, sizeof(*params1)) == 0; } -/** - * __intel_fbc_update - activate/deactivate FBC as needed, unlocked - * @crtc: the CRTC that triggered the update - * - * This function completely reevaluates the status of FBC, then activates, - * deactivates or maintains it on the same state. - */ -static void __intel_fbc_update(struct intel_crtc *crtc) +static 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; - struct intel_fbc_reg_params old_params; WARN_ON(!mutex_is_locked(&fbc->lock)); if (!multiple_pipes_ok(dev_priv)) { set_no_fbc_reason(dev_priv, "more than one pipe active"); - goto out_disable; + goto deactivate; } if (!fbc->enabled || fbc->crtc != crtc) @@ -921,8 +913,25 @@ static void __intel_fbc_update(struct intel_crtc *crtc) intel_fbc_update_state_cache(crtc); - if (!intel_fbc_can_activate(crtc)) - goto out_disable; +deactivate: + __intel_fbc_deactivate(dev_priv); +} + +static void intel_fbc_post_update(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_reg_params old_params; + + WARN_ON(!mutex_is_locked(&fbc->lock)); + + if (!fbc->enabled || fbc->crtc != crtc) + return; + + if (!intel_fbc_can_activate(crtc)) { + WARN_ON(fbc->active); + return; + } old_params = fbc->params; intel_fbc_get_reg_params(crtc, &fbc->params); @@ -936,44 +945,9 @@ static void __intel_fbc_update(struct intel_crtc *crtc) intel_fbc_reg_params_equal(&old_params, &fbc->params)) return; - if (intel_fbc_is_active(dev_priv)) { - /* We update FBC along two paths, after changing fb/crtc - * configuration (modeswitching) and after page-flipping - * finishes. For the latter, we know that not only did - * we disable the FBC at the start of the page-flip - * sequence, but also more than one vblank has passed. - * - * For the former case of modeswitching, it is possible - * to switch between two FBC valid configurations - * instantaneously so we do need to disable the FBC - * before we can modify its control registers. We also - * have to wait for the next vblank for that to take - * effect. However, since we delay enabling FBC we can - * assume that a vblank has passed since disabling and - * that we can safely alter the registers in the deferred - * callback. - * - * In the scenario that we go from a valid to invalid - * and then back to valid FBC configuration we have - * no strict enforcement that a vblank occurred since - * disabling the FBC. However, along all current pipe - * disabling paths we do need to wait for a vblank at - * some point. And we wait before enabling FBC anyway. - */ - DRM_DEBUG_KMS("deactivating FBC for update\n"); - __intel_fbc_deactivate(dev_priv); - } - + __intel_fbc_deactivate(dev_priv); intel_fbc_schedule_activation(crtc); - fbc->no_fbc_reason = "FBC enabled (not necessarily active)"; - return; - -out_disable: - /* Multiple disables should be harmless */ - if (intel_fbc_is_active(dev_priv)) { - DRM_DEBUG_KMS("unsupported config, deactivating FBC\n"); - __intel_fbc_deactivate(dev_priv); - } + fbc->no_fbc_reason = "FBC enabled (active or scheduled)"; } /* @@ -991,7 +965,8 @@ void intel_fbc_update(struct intel_crtc *crtc) return; mutex_lock(&fbc->lock); - __intel_fbc_update(crtc); + intel_fbc_pre_update(crtc); + intel_fbc_post_update(crtc); mutex_unlock(&fbc->lock); } @@ -1045,7 +1020,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, if (fbc->active) intel_fbc_recompress(dev_priv); else - __intel_fbc_update(fbc->crtc); + intel_fbc_post_update(fbc->crtc); } mutex_unlock(&fbc->lock); -- cgit v0.10.2 From 1eb52238a5f5b6a3f497b47e6da39ccfebe6b878 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:44 -0200 Subject: drm/i915/fbc: fix the FBC state checking code We'll now call intel_fbc_pre_update instead of intel_fbc_deactivate during atomic commits. This will continue to guarantee that we deactivate FBC and it will also update the state checking structures at the correct time. Then, later, at the point where we were calling intel_fbc_update, we'll only need to call intel_fbc_post_update. Also add the proper warnings in case we don't have the appropriate locks. Daniel mentioned the warnings will have to be removed for async commits, but let's keep them here while we can. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-12-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 25af606..edd0999 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4799,7 +4799,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_update_watermarks(&crtc->base); if (atomic->update_fbc) - intel_fbc_update(crtc); + intel_fbc_post_update(crtc); if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); @@ -4815,8 +4815,8 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->base.state); - if (atomic->disable_fbc) - intel_fbc_deactivate(crtc); + if (atomic->update_fbc) + intel_fbc_pre_update(crtc); if (crtc->atomic.disable_ips) hsw_disable_ips(crtc); @@ -10912,7 +10912,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit); - intel_fbc_update(crtc); + intel_fbc_post_update(crtc); drm_framebuffer_unreference(work->old_fb); BUG_ON(atomic_read(&crtc->unpin_work_count) == 0); @@ -11712,7 +11712,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); - intel_fbc_deactivate(intel_crtc); + intel_fbc_pre_update(intel_crtc); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); @@ -11901,7 +11901,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, case DRM_PLANE_TYPE_PRIMARY: intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; - intel_crtc->atomic.disable_fbc = true; intel_crtc->atomic.update_fbc = true; if (turn_off) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f620023..b461d73 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -542,16 +542,17 @@ struct intel_mmio_flip { */ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ - bool disable_fbc; bool disable_ips; bool pre_disable_primary; /* Sleepable operations to perform after commit */ unsigned fb_bits; bool wait_vblank; - bool update_fbc; bool post_enable_primary; unsigned update_sprite_watermarks; + + /* Sleepable operations to perform before and after commit */ + bool update_fbc; }; struct intel_crtc { @@ -1330,7 +1331,8 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) /* intel_fbc.c */ bool intel_fbc_is_active(struct drm_i915_private *dev_priv); void intel_fbc_deactivate(struct intel_crtc *crtc); -void intel_fbc_update(struct intel_crtc *crtc); +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_enable(struct intel_crtc *crtc); void intel_fbc_disable(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 61523cd..1c26d65 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -510,6 +510,7 @@ static bool multiple_pipes_ok(struct drm_i915_private *dev_priv) if (INTEL_INFO(dev_priv)->gen > 4) return true; + /* FIXME: we don't have the appropriate state locks to do this here. */ for_each_pipe(dev_priv, pipe) { crtc = dev_priv->pipe_to_crtc_mapping[pipe]; @@ -732,12 +733,16 @@ 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 = crtc->config; + 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 = @@ -896,12 +901,15 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, return memcmp(params1, params2, sizeof(*params1)) == 0; } -static void intel_fbc_pre_update(struct intel_crtc *crtc) +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; - WARN_ON(!mutex_is_locked(&fbc->lock)); + if (!fbc_supported(dev_priv)) + return; + + mutex_lock(&fbc->lock); if (!multiple_pipes_ok(dev_priv)) { set_no_fbc_reason(dev_priv, "more than one pipe active"); @@ -909,15 +917,17 @@ static void intel_fbc_pre_update(struct intel_crtc *crtc) } if (!fbc->enabled || fbc->crtc != crtc) - return; + goto unlock; intel_fbc_update_state_cache(crtc); deactivate: __intel_fbc_deactivate(dev_priv); +unlock: + mutex_unlock(&fbc->lock); } -static void intel_fbc_post_update(struct intel_crtc *crtc) +static void __intel_fbc_post_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; @@ -950,13 +960,7 @@ static void intel_fbc_post_update(struct intel_crtc *crtc) fbc->no_fbc_reason = "FBC enabled (active or scheduled)"; } -/* - * intel_fbc_update - activate/deactivate FBC as needed - * @crtc: the CRTC that triggered the update - * - * This function reevaluates the overall state and activates or deactivates FBC. - */ -void intel_fbc_update(struct intel_crtc *crtc) +void intel_fbc_post_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; @@ -965,8 +969,7 @@ void intel_fbc_update(struct intel_crtc *crtc) return; mutex_lock(&fbc->lock); - intel_fbc_pre_update(crtc); - intel_fbc_post_update(crtc); + __intel_fbc_post_update(crtc); mutex_unlock(&fbc->lock); } @@ -1020,7 +1023,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, if (fbc->active) intel_fbc_recompress(dev_priv); else - intel_fbc_post_update(fbc->crtc); + __intel_fbc_post_update(fbc->crtc); } mutex_unlock(&fbc->lock); -- cgit v0.10.2 From 60eb2cc71c7b581bcd499739f021750c2eb1c8b5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:45 -0200 Subject: drm/i915/fbc: unexport intel_fbc_deactivate With the addition and usage of intel_fbc_pre_update, intel_fbc_deactivate is not used anymore outside intel_fbc.c, so kill the exported function and rename __intel_fbc_deactivate. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-13-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b461d73..ee07bf9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1330,7 +1330,6 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) /* intel_fbc.c */ bool intel_fbc_is_active(struct drm_i915_private *dev_priv); -void intel_fbc_deactivate(struct intel_crtc *crtc); 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); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 1c26d65..74e6bcd 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -444,7 +444,7 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) schedule_work(&work->work); } -static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv) +static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; @@ -456,26 +456,6 @@ static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv) fbc->deactivate(dev_priv); } -/* - * intel_fbc_deactivate - deactivate FBC if it's associated with crtc - * @crtc: the CRTC - * - * This function deactivates FBC if it's associated with the provided CRTC. - */ -void intel_fbc_deactivate(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - struct intel_fbc *fbc = &dev_priv->fbc; - - if (!fbc_supported(dev_priv)) - return; - - mutex_lock(&fbc->lock); - if (fbc->crtc == crtc) - __intel_fbc_deactivate(dev_priv); - mutex_unlock(&fbc->lock); -} - static void set_no_fbc_reason(struct drm_i915_private *dev_priv, const char *reason) { @@ -922,7 +902,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc) intel_fbc_update_state_cache(crtc); deactivate: - __intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv); unlock: mutex_unlock(&fbc->lock); } @@ -955,7 +935,7 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc) intel_fbc_reg_params_equal(&old_params, &fbc->params)) return; - __intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv); intel_fbc_schedule_activation(crtc); fbc->no_fbc_reason = "FBC enabled (active or scheduled)"; } @@ -998,7 +978,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; if (fbc->busy_bits) - __intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv); mutex_unlock(&fbc->lock); } -- cgit v0.10.2 From c937ab3e584ea66433ce743a42c752e31f3acdbe Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:46 -0200 Subject: drm/i915/fbc: rename the FBC disable functions Instead of: - intel_fbc_disable_crtc(crtc) - intel_fbc_disable(dev_priv) we now have: - intel_fbc_disable(crtc) - intel_fbc_global_disable(dev_priv) This is because all the other functions that take a CRTC are called - intel_fbc_something(crtc) Instead of: - intel_fbc_something_crtc(crtc) And I also hope that the word "global" is going to help make it more explicit that "global" is the unusual case, not the opposite. Reported-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-14-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index a2aa09c..6c6bedf 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -92,7 +92,7 @@ static void i915_restore_display(struct drm_device *dev) } /* only restore FBC info on the platform that supports FBC*/ - intel_fbc_disable(dev_priv); + intel_fbc_global_disable(dev_priv); /* restore FBC interval */ if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index edd0999..60108e6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5124,7 +5124,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); - intel_fbc_disable_crtc(intel_crtc); + intel_fbc_disable(intel_crtc); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5176,7 +5176,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) true); } - intel_fbc_disable_crtc(intel_crtc); + intel_fbc_disable(intel_crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6352,7 +6352,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - intel_fbc_disable_crtc(intel_crtc); + intel_fbc_disable(intel_crtc); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) @@ -16041,7 +16041,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - intel_fbc_disable(dev_priv); + intel_fbc_global_disable(dev_priv); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ee07bf9..06b04ac 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1334,8 +1334,8 @@ 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_enable(struct intel_crtc *crtc); -void intel_fbc_disable(struct drm_i915_private *dev_priv); -void intel_fbc_disable_crtc(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, unsigned int frontbuffer_bits, enum fb_op_origin origin); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 74e6bcd..0478343 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1078,12 +1078,12 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) } /** - * intel_fbc_disable_crtc - disable FBC if it's associated with crtc + * intel_fbc_disable - disable FBC if it's associated with crtc * @crtc: the CRTC * * This function disables FBC if it's associated with the provided CRTC. */ -void intel_fbc_disable_crtc(struct intel_crtc *crtc) +void intel_fbc_disable(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; @@ -1101,12 +1101,12 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) } /** - * intel_fbc_disable - globally disable FBC + * intel_fbc_global_disable - globally disable FBC * @dev_priv: i915 device instance * * This function disables FBC regardless of which CRTC is associated with it. */ -void intel_fbc_disable(struct drm_i915_private *dev_priv) +void intel_fbc_global_disable(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; -- cgit v0.10.2 From 65c7600f07d4eb372c078dcd7138a9276f5705eb Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:47 -0200 Subject: drm/i915/fbc: make sure we cancel the work function at fbc_disable Just to be sure nothing will survive a module unload. We need to do this after the unlock in order to make sure the function won't get stuck trying to grab the lock we already own while we wait for it to finish. Reported-by: Reported-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-15-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 0478343..35d2650 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1098,6 +1098,8 @@ void intel_fbc_disable(struct intel_crtc *crtc) __intel_fbc_disable(dev_priv); } mutex_unlock(&fbc->lock); + + cancel_work_sync(&fbc->work.work); } /** @@ -1117,6 +1119,8 @@ void intel_fbc_global_disable(struct drm_i915_private *dev_priv) if (fbc->enabled) __intel_fbc_disable(dev_priv); mutex_unlock(&fbc->lock); + + cancel_work_sync(&fbc->work.work); } /** -- cgit v0.10.2 From 010cf73d4648df35585c0c326123b04ab79e4573 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:48 -0200 Subject: drm/i915/fbc: rewrite the multiple_pipes_ok() code for locking Older FBC platforms have this restriction where FBC can't be enabled if multiple pipes are enabled. In the current code, we disable FBC before the second pipe becomes visible. One of the problems with this code is that the current multiple_pipes_ok() implementation just iterates through all CRTCs looking at their states, but it doesn't make sure that the state locks are grabbed. It also can't just grab the locks for every CRTC since this would kill one of the biggest advantages of atomic modesetting. After the recent FBC changes, we now have the appropriate locks for the given CRTC, so we can just try to maintain the state of each CRTC and update it once intel_fbc_pre_update is called. As a last note, I don't have gen 2/3 machines to test this code. My current plan is to enable FBC on just the newer platforms, so this patch is just an attempt to get the gen 2/3 code at least looking sane, so if one day someone decide to fix FBC on these platforms, they may have less work to do. Not-tested-by: Paulo Zanoni (only on HSW+) Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-16-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0df9913..e4da97c6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -907,6 +907,7 @@ struct intel_fbc { unsigned threshold; unsigned int possible_framebuffer_bits; unsigned int busy_bits; + unsigned int visible_pipes_mask; struct intel_crtc *crtc; struct drm_mm_node compressed_fb; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60108e6..136668a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15912,6 +15912,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev) modeset_put_power_domains(dev_priv, put_domains); } intel_display_set_init_power(dev_priv, false); + + intel_fbc_init_pipe_state(dev_priv); } void intel_display_resume(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 06b04ac..00a8359 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1333,6 +1333,7 @@ bool intel_fbc_is_active(struct drm_i915_private *dev_priv); 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); void intel_fbc_disable(struct intel_crtc *crtc); void intel_fbc_global_disable(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 35d2650..c2ef400 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -56,6 +56,11 @@ static inline bool fbc_on_plane_a_only(struct drm_i915_private *dev_priv) return INTEL_INFO(dev_priv)->gen < 4; } +static inline bool no_fbc_on_multiple_pipes(struct drm_i915_private *dev_priv) +{ + return INTEL_INFO(dev_priv)->gen <= 3; +} + /* * In some platforms where the CRTC's x:0/y:0 coordinates doesn't match the * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's @@ -481,25 +486,25 @@ static bool crtc_can_fbc(struct intel_crtc *crtc) return true; } -static bool multiple_pipes_ok(struct drm_i915_private *dev_priv) +static bool multiple_pipes_ok(struct intel_crtc *crtc) { - enum pipe pipe; - int n_pipes = 0; - struct drm_crtc *crtc; + 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; - if (INTEL_INFO(dev_priv)->gen > 4) + /* Don't even bother tracking anything we don't need. */ + if (!no_fbc_on_multiple_pipes(dev_priv)) return true; - /* FIXME: we don't have the appropriate state locks to do this here. */ - for_each_pipe(dev_priv, pipe) { - crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + WARN_ON(!drm_modeset_is_locked(&primary->mutex)); - if (intel_crtc_active(crtc) && - to_intel_plane_state(crtc->primary->state)->visible) - n_pipes++; - } + if (to_intel_plane_state(primary->state)->visible) + fbc->visible_pipes_mask |= (1 << pipe); + else + fbc->visible_pipes_mask &= ~(1 << pipe); - return (n_pipes < 2); + return (fbc->visible_pipes_mask & ~(1 << pipe)) != 0; } static int find_compression_threshold(struct drm_i915_private *dev_priv, @@ -891,7 +896,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc) mutex_lock(&fbc->lock); - if (!multiple_pipes_ok(dev_priv)) { + if (!multiple_pipes_ok(crtc)) { set_no_fbc_reason(dev_priv, "more than one pipe active"); goto deactivate; } @@ -1124,6 +1129,28 @@ void intel_fbc_global_disable(struct drm_i915_private *dev_priv) } /** + * intel_fbc_init_pipe_state - initialize FBC's CRTC visibility tracking + * @dev_priv: i915 device instance + * + * The FBC code needs to track CRTC visibility since the older platforms can't + * have FBC enabled while multiple pipes are used. This function does the + * initial setup at driver load to make sure FBC is matching the real hardware. + */ +void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv) +{ + struct intel_crtc *crtc; + + /* Don't even bother tracking anything if we don't need. */ + if (!no_fbc_on_multiple_pipes(dev_priv)) + return; + + for_each_intel_crtc(dev_priv->dev, crtc) + if (intel_crtc_active(&crtc->base) && + to_intel_plane_state(crtc->base.primary->state)->visible) + dev_priv->fbc.visible_pipes_mask |= (1 << crtc->pipe); +} + +/** * intel_fbc_init - Initialize FBC * @dev_priv: the i915 device * -- cgit v0.10.2 From dd8b3bdbdb748e1ae6a7025bf113ab08b09952bb Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:49 -0200 Subject: drm/i915: simplify struct drm_device access at intel_atomic_check() We already have a dev variable, there's no need to access state->dev. Also, I plan to add another dev_priv user here, so declare one for the current user. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-17-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 136668a..189367c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13327,6 +13327,7 @@ static void calc_watermark_data(struct drm_atomic_state *state) static int intel_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(dev); struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -13369,7 +13370,7 @@ static int intel_atomic_check(struct drm_device *dev, return ret; if (i915.fastboot && - intel_pipe_config_compare(state->dev, + intel_pipe_config_compare(dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { crtc_state->mode_changed = false; @@ -13395,9 +13396,9 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; } else - intel_state->cdclk = to_i915(state->dev)->cdclk_freq; + intel_state->cdclk = dev_priv->cdclk_freq; - ret = drm_atomic_helper_check_planes(state->dev, state); + ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; -- cgit v0.10.2 From f51be2e0e3c54b7146152b39c1b5f569a005ab79 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:50 -0200 Subject: drm/i915/fbc: choose the new FBC CRTC during atomic check This opens the possibility of implementing nicer schemes to choose the CRTC, such as checking the amount of stolen memory available, or choosing the best pipe on platforms that don't die FBC to pipe or plane A. This code was written for another refactor that I ended up discarding, so I don't actually need it, but I figured this patch would be an improvement on its own so I kept it on the series. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-18-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 189367c..cd57613 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13402,6 +13402,7 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; + intel_fbc_choose_crtc(dev_priv, state); calc_watermark_data(state); return 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 00a8359..93ba14a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -492,6 +492,8 @@ struct intel_crtc_state { bool ips_enabled; + bool enable_fbc; + bool double_wide; bool dp_encoder_is_mst; @@ -1329,6 +1331,8 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) #endif /* intel_fbc.c */ +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); void intel_fbc_post_update(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index c2ef400..5bf7f84 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -826,7 +826,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) return true; } -static bool intel_fbc_can_enable(struct intel_crtc *crtc) +static bool intel_fbc_can_choose(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -1015,11 +1015,76 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, } /** + * intel_fbc_choose_crtc - select a CRTC to enable FBC on + * @dev_priv: i915 device instance + * @state: the atomic state structure + * + * This function looks at the proposed state for CRTCs and planes, then chooses + * which pipe is going to have FBC by setting intel_crtc_state->enable_fbc to + * true. + * + * Later, intel_fbc_enable is going to look for state->enable_fbc and then maybe + * enable FBC for the chosen CRTC. If it does, it will set dev_priv->fbc.crtc. + */ +void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv, + struct drm_atomic_state *state) +{ + struct intel_fbc *fbc = &dev_priv->fbc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_plane_state *plane_state; + bool fbc_crtc_present = false; + int i, j; + + mutex_lock(&fbc->lock); + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (fbc->crtc == to_intel_crtc(crtc)) { + fbc_crtc_present = true; + break; + } + } + /* This atomic commit doesn't involve the CRTC currently tied to FBC. */ + if (!fbc_crtc_present && fbc->crtc != NULL) + goto out; + + /* Simply choose the first CRTC that is compatible and has a visible + * plane. We could go for fancier schemes such as checking the plane + * size, but this would just affect the few platforms that don't tie FBC + * to pipe or plane A. */ + for_each_plane_in_state(state, plane, plane_state, i) { + struct intel_plane_state *intel_plane_state = + to_intel_plane_state(plane_state); + + if (!intel_plane_state->visible) + continue; + + for_each_crtc_in_state(state, crtc, crtc_state, j) { + struct intel_crtc_state *intel_crtc_state = + to_intel_crtc_state(crtc_state); + + if (plane_state->crtc != crtc) + continue; + + if (!intel_fbc_can_choose(to_intel_crtc(crtc))) + break; + + intel_crtc_state->enable_fbc = true; + goto out; + } + } + +out: + mutex_unlock(&fbc->lock); +} + +/** * intel_fbc_enable: tries to enable FBC on the CRTC * @crtc: the CRTC * - * This function checks if it's possible to enable FBC on the following CRTC, - * then enables it. Notice that it doesn't activate FBC. + * This function checks if the given CRTC was chosen for FBC, then enables it if + * possible. Notice that it doesn't activate FBC. */ void intel_fbc_enable(struct intel_crtc *crtc) { @@ -1036,12 +1101,12 @@ void intel_fbc_enable(struct intel_crtc *crtc) goto out; } + if (!crtc->config->enable_fbc) + goto out; + WARN_ON(fbc->active); WARN_ON(fbc->crtc != NULL); - if (!intel_fbc_can_enable(crtc)) - goto out; - intel_fbc_update_state_cache(crtc); if (intel_fbc_alloc_cfb(crtc)) { set_no_fbc_reason(dev_priv, "not enough stolen memory"); -- cgit v0.10.2 From 58f9c0bc557588fbe3f54c521dd8c6f20598e64e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:51 -0200 Subject: drm/i915/fbc: move intel_fbc_{enable, disable} call one level up Instead of duplicating the calls for every platform, let's just put them in the correct places inside intel_atomic_commit. This will also make it easier for us to move the enable call in order to support fasbtoot. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-19-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cd57613..69ab077 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4927,8 +4927,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config->has_pch_encoder) intel_wait_for_vblank(dev, pipe); intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); - - intel_fbc_enable(intel_crtc); } /* IPS only exists on ULT machines and is tied to pipe A. */ @@ -5041,8 +5039,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_wait_for_vblank(dev, hsw_workaround_pipe); intel_wait_for_vblank(dev, hsw_workaround_pipe); } - - intel_fbc_enable(intel_crtc); } static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force) @@ -5123,8 +5119,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) } intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); - - intel_fbc_disable(intel_crtc); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5175,8 +5169,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, true); } - - intel_fbc_disable(intel_crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6287,8 +6279,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); - - intel_fbc_enable(intel_crtc); } static void i9xx_pfit_disable(struct intel_crtc *crtc) @@ -6351,8 +6341,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - - intel_fbc_disable(intel_crtc); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) @@ -6376,6 +6364,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) dev_priv->display.crtc_disable(crtc); intel_crtc->active = false; + intel_fbc_disable(intel_crtc); intel_update_watermarks(crtc); intel_disable_shared_dpll(intel_crtc); @@ -13529,6 +13518,7 @@ static int intel_atomic_commit(struct drm_device *dev, intel_crtc_disable_planes(crtc, crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); intel_crtc->active = false; + intel_fbc_disable(intel_crtc); intel_disable_shared_dpll(intel_crtc); /* @@ -13568,6 +13558,7 @@ static int intel_atomic_commit(struct drm_device *dev, if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); + intel_fbc_enable(intel_crtc); } if (update_pipe) { diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 5bf7f84..60644dd 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1137,7 +1137,7 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) WARN_ON(!mutex_is_locked(&fbc->lock)); WARN_ON(!fbc->enabled); WARN_ON(fbc->active); - assert_pipe_disabled(dev_priv, crtc->pipe); + WARN_ON(crtc->active); DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe)); -- cgit v0.10.2 From 49227c4ae3d2c8ccb6c71bfb5dfac80ad8c73021 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:52 -0200 Subject: drm/i915/fbc: make FBC work with fastboot Move intel_fbc_enable to a place where it is called regardless of the "modeset" variable, and make sure intel_fbc_enable can be called multiple times without intel_fbc_disable being called. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-20-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 69ab077..a832ff1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13558,7 +13558,6 @@ static int intel_atomic_commit(struct drm_device *dev, if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); - intel_fbc_enable(intel_crtc); } if (update_pipe) { @@ -13571,6 +13570,9 @@ static int intel_atomic_commit(struct drm_device *dev, if (!modeset) intel_pre_plane_update(intel_crtc); + if (crtc->state->active && intel_crtc->atomic.update_fbc) + intel_fbc_enable(intel_crtc); + if (crtc->state->active && (crtc->state->planes_changed || update_pipe)) drm_atomic_helper_commit_planes_on_crtc(crtc_state); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 60644dd..912b953 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1084,7 +1084,9 @@ out: * @crtc: the CRTC * * This function checks if the given CRTC was chosen for FBC, then enables it if - * possible. Notice that it doesn't activate FBC. + * possible. Notice that it doesn't activate FBC. It is valid to call + * 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) { @@ -1097,7 +1099,11 @@ void intel_fbc_enable(struct intel_crtc *crtc) mutex_lock(&fbc->lock); if (fbc->enabled) { - WARN_ON(fbc->crtc == crtc); + WARN_ON(fbc->crtc == NULL); + if (fbc->crtc == crtc) { + WARN_ON(!crtc->config->enable_fbc); + WARN_ON(fbc->active); + } goto out; } -- cgit v0.10.2 From 5bc40472dea771260dc6d6946fd09c1ac3c9cd93 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:53 -0200 Subject: drm/i915/fbc: don't try to deactivate FBC if it's not enabled During FBC invalidation, don't call intel_fbc_deactivate if it's not enabled. This doesn't fix any bug, but helps making the interface saner. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-21-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 912b953..2ed9be2 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -982,7 +982,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; - if (fbc->busy_bits) + if (fbc->enabled && fbc->busy_bits) intel_fbc_deactivate(dev_priv); mutex_unlock(&fbc->lock); -- cgit v0.10.2 From 913a3a6acae3c90e07f96c849c2a071b27a0fc1d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:54 -0200 Subject: drm/i915/fbc: don't print no_fbc_reason to dmesg Our dmesg messages started being misleading after we converted to the enable+activate model: we always print "Disabling FBC", even when we're just deactivating it. So, for example, when I boot my machine and do "dmesg | grep -i fbc", I see: [drm:intel_fbc_enable] Enabling FBC on pipe A [drm:set_no_fbc_reason] Disabling FBC: framebuffer not tiled or fenced but then, if I read the debugfs file, I will see: $ sudo cat i915_fbc_status FBC enabled Compressing: yes so we can conclude that dmesg is misleading, since FBC is actually enabled. What happened is that we deactivated FBC due to fbcon not being tiled, but when we silently reactivated it when the display manager started. We don't print activation messages since there may be way too many of these operations per second during normal desktop usage. One possible solution would be to change set_no_fbc_reason to correctly differentiate between disable and deactivation, but we removed support from printing activation/deactivation messages in the past because they were too frequent. So instead of doing this, let's just not print anything on dmesg, and leave the debugfs file if the user needs to investigate something. We already print when we enable and disable FBC anyway on a given pipe, so this should already help triaging bugs. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-22-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 2ed9be2..cdd99cf 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -461,18 +461,6 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) fbc->deactivate(dev_priv); } -static void set_no_fbc_reason(struct drm_i915_private *dev_priv, - const char *reason) -{ - struct intel_fbc *fbc = &dev_priv->fbc; - - if (fbc->no_fbc_reason == reason) - return; - - fbc->no_fbc_reason = reason; - DRM_DEBUG_KMS("Disabling FBC: %s\n", reason); -} - static bool crtc_can_fbc(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -761,18 +749,18 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) struct intel_fbc_state_cache *cache = &fbc->state_cache; if (!cache->plane.visible) { - set_no_fbc_reason(dev_priv, "primary plane not visible"); + fbc->no_fbc_reason = "primary plane not visible"; return false; } if ((cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) || (cache->crtc.mode_flags & DRM_MODE_FLAG_DBLSCAN)) { - set_no_fbc_reason(dev_priv, "incompatible mode"); + fbc->no_fbc_reason = "incompatible mode"; return false; } if (!intel_fbc_hw_tracking_covers_screen(crtc)) { - set_no_fbc_reason(dev_priv, "mode too large for compression"); + fbc->no_fbc_reason = "mode too large for compression"; return false; } @@ -781,29 +769,29 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) */ if (cache->fb.tiling_mode != I915_TILING_X || cache->fb.fence_reg == I915_FENCE_REG_NONE) { - set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced"); + fbc->no_fbc_reason = "framebuffer not tiled or fenced"; return false; } if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && cache->plane.rotation != BIT(DRM_ROTATE_0)) { - set_no_fbc_reason(dev_priv, "rotation unsupported"); + fbc->no_fbc_reason = "rotation unsupported"; return false; } if (!stride_is_valid(dev_priv, cache->fb.stride)) { - set_no_fbc_reason(dev_priv, "framebuffer stride not supported"); + fbc->no_fbc_reason = "framebuffer stride not supported"; return false; } if (!pixel_format_is_valid(dev_priv, cache->fb.pixel_format)) { - set_no_fbc_reason(dev_priv, "pixel format is invalid"); + fbc->no_fbc_reason = "pixel format is invalid"; return false; } /* WaFbcExceedCdClockThreshold:hsw,bdw */ if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) && cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk_freq * 95 / 100) { - set_no_fbc_reason(dev_priv, "pixel rate is too big"); + fbc->no_fbc_reason = "pixel rate is too big"; return false; } @@ -819,7 +807,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) * important case, we can implement it later. */ if (intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache) > fbc->compressed_fb.size * fbc->threshold) { - set_no_fbc_reason(dev_priv, "CFB requirements changed"); + fbc->no_fbc_reason = "CFB requirements changed"; return false; } @@ -829,24 +817,25 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) static bool intel_fbc_can_choose(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_fbc *fbc = &dev_priv->fbc; if (intel_vgpu_active(dev_priv->dev)) { - set_no_fbc_reason(dev_priv, "VGPU is active"); + fbc->no_fbc_reason = "VGPU is active"; return false; } if (i915.enable_fbc < 0) { - set_no_fbc_reason(dev_priv, "disabled per chip default"); + fbc->no_fbc_reason = "disabled per chip default"; return false; } if (!i915.enable_fbc) { - set_no_fbc_reason(dev_priv, "disabled per module param"); + fbc->no_fbc_reason = "disabled per module param"; return false; } if (!crtc_can_fbc(crtc)) { - set_no_fbc_reason(dev_priv, "no enabled pipes can have FBC"); + fbc->no_fbc_reason = "no enabled pipes can have FBC"; return false; } @@ -897,7 +886,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc) mutex_lock(&fbc->lock); if (!multiple_pipes_ok(crtc)) { - set_no_fbc_reason(dev_priv, "more than one pipe active"); + fbc->no_fbc_reason = "more than one pipe active"; goto deactivate; } @@ -1115,7 +1104,7 @@ void intel_fbc_enable(struct intel_crtc *crtc) intel_fbc_update_state_cache(crtc); if (intel_fbc_alloc_cfb(crtc)) { - set_no_fbc_reason(dev_priv, "not enough stolen memory"); + fbc->no_fbc_reason = "not enough stolen memory"; goto out; } -- cgit v0.10.2 From b20d27526cb0e8dd2b7db3b45ec96aecfc02d610 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:55 -0200 Subject: drm/i915/fbc: don't store the fb_id on reg_params We don't actually use fb_id anywhere. We already compare all parameters that matter to the hardware: pixel format, stride, fence_reg and ggtt_offset. The ID shouldn't make a difference. Besides, we already update the FBC data at every modeset/flip, so this can't change behind our backs. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-23-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e4da97c6..52cd352 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -933,7 +933,6 @@ struct intel_fbc { struct { u64 ilk_ggtt_offset; - uint32_t id; uint32_t pixel_format; unsigned int stride; int fence_reg; @@ -950,7 +949,6 @@ struct intel_fbc { struct { u64 ggtt_offset; - uint32_t id; uint32_t pixel_format; unsigned int stride; int fence_reg; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index cdd99cf..35e92bc 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -735,7 +735,6 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc) * platforms that need. */ if (dev_priv->fbc.activate == ilk_fbc_activate) cache->fb.ilk_ggtt_offset = i915_gem_obj_ggtt_offset(obj); - cache->fb.id = fb->base.id; cache->fb.pixel_format = fb->pixel_format; cache->fb.stride = fb->pitches[0]; cache->fb.fence_reg = obj->fence_reg; @@ -858,7 +857,6 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, params->crtc.plane = crtc->plane; params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc); - params->fb.id = cache->fb.id; params->fb.pixel_format = cache->fb.pixel_format; params->fb.stride = cache->fb.stride; params->fb.fence_reg = cache->fb.fence_reg; -- cgit v0.10.2 From e8216e502acaad129210c3c8b30cb4ab41e70239 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 19 Jan 2016 11:35:56 -0200 Subject: drm/i915/fbc: call intel_fbc_pre_update earlier during page flips Make sure we do the pre_update - which also deactivates FBC - before we actually schedule the page flip, just to make sure we don't flip to the new FB with FBC still activated for the previous FB. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-24-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a832ff1..a66220a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11617,6 +11617,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, crtc->primary->fb = fb; update_state_fb(crtc->primary); + intel_fbc_pre_update(intel_crtc); work->pending_flip_obj = obj; @@ -11701,7 +11702,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); - intel_fbc_pre_update(intel_crtc); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); -- cgit v0.10.2 From 9b42281f9ddafe459e0b0d91ddf1939fbf84d832 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Jan 2016 15:45:56 -0200 Subject: drm/i915/fbc: don't store/check a pointer to the FB We already make sure we run intel_fbc_update_update during modesets and page flips, and this function takes care of deactivating FBC, so it shouldn't be possible for us to reach the condition we check at intel_fbc_work_fn. So instead of grabbing framebuffer references and adding a lot of code to track when we need to free them, just don't track anything at all since we shouldn't need to. v2: Rebase. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-25-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 52cd352..c921ad8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -961,7 +961,6 @@ struct intel_fbc { bool scheduled; u32 scheduled_vblank; struct work_struct work; - struct drm_framebuffer *fb; } work; const char *no_fbc_reason; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 35e92bc..2c896f9 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -405,8 +405,7 @@ retry: goto retry; } - if (crtc->base.primary->fb == work->fb) - fbc->activate(dev_priv); + fbc->activate(dev_priv); work->scheduled = false; @@ -441,7 +440,6 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) * we're not releasing fbc.lock, so it won't have an opportunity to grab * it to discover that it was cancelled. So we just update the expected * jiffy count. */ - work->fb = crtc->base.primary->fb; work->scheduled = true; work->scheduled_vblank = drm_crtc_vblank_count(&crtc->base); drm_crtc_vblank_put(&crtc->base); -- cgit v0.10.2 From e35be23f31c9bd42c342aca519bcedbc34b35da4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 18 Jan 2016 15:56:58 -0200 Subject: drm/i915/fbc: refactor some small functions called only once The FBC fixes we've been doing in the last months required a lot of refactor, so functions that were once big and called from different spots are now small and called only once. IMHO now it's better to just move the contents of these functions to their only callers since this reduces the number of indirections while reading the code. While at it, also improve the related comments a little bit. Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-26-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 2c896f9..5adf6d7 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -414,14 +414,6 @@ out: drm_crtc_vblank_put(&crtc->base); } -static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) -{ - struct intel_fbc *fbc = &dev_priv->fbc; - - WARN_ON(!mutex_is_locked(&fbc->lock)); - fbc->work.scheduled = false; -} - static void intel_fbc_schedule_activation(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -436,10 +428,10 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) return; } - /* It is useless to call intel_fbc_cancel_work() in this function since - * we're not releasing fbc.lock, so it won't have an opportunity to grab - * it to discover that it was cancelled. So we just update the expected - * jiffy count. */ + /* It is useless to call intel_fbc_cancel_work() or cancel_work() in + * this function since we're not releasing fbc.lock, so it won't have an + * opportunity to grab it to discover that it was cancelled. So we just + * update the expected jiffy count. */ work->scheduled = true; work->scheduled_vblank = drm_crtc_vblank_count(&crtc->base); drm_crtc_vblank_put(&crtc->base); @@ -453,25 +445,15 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) WARN_ON(!mutex_is_locked(&fbc->lock)); - intel_fbc_cancel_work(dev_priv); + /* Calling cancel_work() here won't help due to the fact that the work + * function grabs fbc->lock. Just set scheduled to false so the work + * function can know it was cancelled. */ + fbc->work.scheduled = false; if (fbc->active) fbc->deactivate(dev_priv); } -static bool crtc_can_fbc(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - - if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A) - return false; - - if (fbc_on_plane_a_only(dev_priv) && crtc->plane != PLANE_A) - return false; - - return true; -} - static bool multiple_pipes_ok(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -831,11 +813,16 @@ static bool intel_fbc_can_choose(struct intel_crtc *crtc) return false; } - if (!crtc_can_fbc(crtc)) { + if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A) { fbc->no_fbc_reason = "no enabled pipes can have FBC"; return false; } + if (fbc_on_plane_a_only(dev_priv) && crtc->plane != PLANE_A) { + fbc->no_fbc_reason = "no enabled planes can have FBC"; + return false; + } + return true; } -- cgit v0.10.2 From dc5a9037141924c0867eb4a6e5220479dcda84f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 29 Jan 2016 14:44:59 -0800 Subject: drm/i915: Sink CRC: tune down error message at stop to debug_kms. When we stop the sink CRC calculation we wait a while until the counter is reset to zero and return -ETIMEDOUT. However the sink crc was calculated already by this point so we just ignore this return at the main function. So, let's also ignore the message and put it as a debug message instead of an error one. The message might still be useful when debuging test failures so we could be able to know something was not going so well with sink crc stop. v2: Improve log message. Reference: https://bugs.freedesktop.org/show_bug.cgi?id=93694 Cc: Daniel Vetter Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1454107499-29678-1-git-send-email-rodrigo.vivi@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e2bea710..f44aba1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4008,7 +4008,7 @@ static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp) } while (--attempts && count); if (attempts == 0) { - DRM_ERROR("TIMEOUT: Sink CRC counter is not zeroed\n"); + DRM_DEBUG_KMS("TIMEOUT: Sink CRC counter is not zeroed after calculation is stopped\n"); ret = -ETIMEDOUT; } -- cgit v0.10.2 From a41c8882592fb80458959b10e37632ce030b68ca Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Thu, 28 Jan 2016 15:19:23 -0800 Subject: drm/i915/skl: Fix DMC load on Skylake J0 and K0 The driver does not load firmware for unknown steppings, so these new steppings must be added to the list. Cc: Rodrigo Vivi Signed-off-by: Mat Martineau Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: http://patchwork.freedesktop.org/patch/msgid/1454023163-25469-1-git-send-email-mathew.j.martineau@linux.intel.com diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 5c2f9a4..2a7ec31 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -179,7 +179,8 @@ static const struct stepping_info kbl_stepping_info[] = { static const struct stepping_info skl_stepping_info[] = { {'A', '0'}, {'B', '0'}, {'C', '0'}, {'D', '0'}, {'E', '0'}, {'F', '0'}, - {'G', '0'}, {'H', '0'}, {'I', '0'} + {'G', '0'}, {'H', '0'}, {'I', '0'}, + {'J', '0'}, {'K', '0'} }; static const struct stepping_info bxt_stepping_info[] = { -- cgit v0.10.2 From dc9b5a0c631115118267255837ac9df682fb79d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 1 Feb 2016 12:02:06 -0800 Subject: drm/i915: PSR simplify port and link standby checks. Current code not just block link_standby for non DDI platforms but also block PSR from work on other ports B/C/D/E. So, besides change any behaviour let's just fix the mess a bit here and reuse HSW check to block the other ports and reduce the second if only to link stadnby request. Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 9ccff30..3c80b86 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -304,8 +304,15 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) dev_priv->psr.source_ok = false; - if (IS_HASWELL(dev) && dig_port->port != PORT_A) { - DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n"); + /* + * HSW spec explicitly says PSR is tied to port A. + * BDW+ platforms with DDI implementation of PSR have different + * PSR registers per transcoder and we only implement transcoder EDP + * ones. Since by Display design transcoder EDP is tied to port A + * we can safely escape based on the port A. + */ + if (HAS_DDI(dev) && dig_port->port != PORT_A) { + DRM_DEBUG_KMS("PSR condition failed: Port not supported\n"); return false; } @@ -328,7 +335,7 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) } if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && - ((dev_priv->vbt.psr.full_link) || (dig_port->port != PORT_A))) { + dev_priv->vbt.psr.full_link) { DRM_DEBUG_KMS("PSR condition failed: Link Standby requested/needed but not supported on this platform\n"); return false; } -- cgit v0.10.2 From 60e5ffe329b090155ec860e2f31dc8d505ec7acd Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 1 Feb 2016 12:02:07 -0800 Subject: drm/i915: Add PSR main link standby support back Link standby support has been deprecated with 'commit 89251b177 ("drm/i915: PSR: deprecate link_standby support for core platforms.")' The reason for that is that main link in full off offers more power savings and on HSW and BDW implementations on source side had known bugs with link standby. However that same HSD report only mentions BDW and HSW and tells that a fix was going to new platforms. Since on Skylake link standby didn't cause the bad blank flickering screens seen on HSW and BDW let's respect VBT again for this and future platforms. Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 863012a..ec0c2a05e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2583,6 +2583,10 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) enabled = true; } } + + seq_printf(m, "Main link in standby mode: %s\n", + yesno(dev_priv->psr.link_standby)); + seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled)); if (!HAS_DDI(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c921ad8..65a2cd0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1007,6 +1007,7 @@ struct i915_psr { unsigned busy_frontbuffer_bits; bool psr2_support; bool aux_frame_sync; + bool link_standby; }; enum intel_pch { diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 3c80b86..b99a105 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -225,7 +225,12 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); } - drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, DP_PSR_ENABLE); + if (dev_priv->psr.link_standby) + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); + else + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, + DP_PSR_ENABLE); } static void vlv_psr_enable_source(struct intel_dp *intel_dp) @@ -280,6 +285,9 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp) if (IS_HASWELL(dev)) val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; + if (dev_priv->psr.link_standby) + val |= EDP_PSR_LINK_STANDBY; + I915_WRITE(EDP_PSR_CTL, val | max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | idle_frames << EDP_PSR_IDLE_FRAME_SHIFT | @@ -334,12 +342,6 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return false; } - if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && - dev_priv->vbt.psr.full_link) { - DRM_DEBUG_KMS("PSR condition failed: Link Standby requested/needed but not supported on this platform\n"); - return false; - } - dev_priv->psr.source_ok = true; return true; } @@ -770,6 +772,16 @@ void intel_psr_init(struct drm_device *dev) dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ? HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE; + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + /* HSW and BDW require workarounds that we don't implement. */ + dev_priv->psr.link_standby = false; + else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) + /* On VLV and CHV only standby mode is supported. */ + dev_priv->psr.link_standby = true; + else + /* For new platforms let's respect VBT back again */ + dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; + INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); } -- cgit v0.10.2 From 65f61b426ddba160699fd64bf94f14eff339616c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 1 Feb 2016 12:02:08 -0800 Subject: drm/i915: Instrument PSR parameter for debuging with link standby x link off. Unfortunately we don't know all panels and platforms out there and we found internal prototypes without VBT proper set but where only link in standby worked well. So, before enable PSR by default let's instrument the PSR parameter in a way that we can identify different panels out there that might require or work better with link standby mode. It is also useful to say that for backward compatibility I'm not changing the meaning of this flag. So "0" still means disabled and "1" means enabled with full support and maximum power savings. v2: Use positive value instead of negative for different operation mode as suggested by Daniel. v3: As Paulo suggested use 2 to force link standby and 3 to force link fully on. Also split the link_standby introduction in a separated patch. v4: Use DRM_ERROR for link off request on platforms that don't support and Remove the quirk promise. Cc: Jani Nikula Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Rodrigo Vivi Link: http://patchwork.freedesktop.org/patch/msgid/1454356928-19779-1-git-send-email-rodrigo.vivi@intel.com diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 8d90c25..8b9f368 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -127,7 +127,8 @@ MODULE_PARM_DESC(enable_execlists, "(-1=auto [default], 0=disabled, 1=enabled)"); module_param_named_unsafe(enable_psr, i915.enable_psr, int, 0600); -MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)"); +MODULE_PARM_DESC(enable_psr, "Enable PSR " + "(0=disabled [default], 1=enabled - link mode chosen per-platform, 2=force link-standby mode, 3=force link-off mode)"); module_param_named_unsafe(preliminary_hw_support, i915.preliminary_hw_support, int, 0600); MODULE_PARM_DESC(preliminary_hw_support, diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index b99a105..4ab7579 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -329,6 +329,12 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return false; } + if ((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) && + !dev_priv->psr.link_standby) { + DRM_ERROR("PSR condition failed: Link off requested but not supported on this platform\n"); + return false; + } + if (IS_HASWELL(dev) && I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config->cpu_transcoder)) & S3D_ENABLE) { @@ -772,6 +778,7 @@ void intel_psr_init(struct drm_device *dev) dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ? HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE; + /* Set link_standby x link_off defaults */ if (IS_HASWELL(dev) || IS_BROADWELL(dev)) /* HSW and BDW require workarounds that we don't implement. */ dev_priv->psr.link_standby = false; @@ -782,6 +789,16 @@ void intel_psr_init(struct drm_device *dev) /* For new platforms let's respect VBT back again */ dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; + /* Override link_standby x link_off defaults */ + if (i915.enable_psr == 2 && !dev_priv->psr.link_standby) { + DRM_DEBUG_KMS("PSR: Forcing link standby\n"); + dev_priv->psr.link_standby = true; + } + if (i915.enable_psr == 3 && dev_priv->psr.link_standby) { + DRM_DEBUG_KMS("PSR: Forcing main link off\n"); + dev_priv->psr.link_standby = false; + } + INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); } -- cgit v0.10.2 From bf4f2fb05f89ac50de024b1a5dd0cd0db4a8f845 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 20 Jan 2016 15:31:20 +0100 Subject: drm/i915/skl/kbl: Add support for pipe fusing On SKL and KBL we can have pipe A/B/C disabled by fuse settings. The pipes must be fused in descending order (e.g. C, B+C, A+B+C). We simply decrease info->num_pipes if we find a valid fused out config. v2: Don't store the pipe disabled mask in device info (Damien) v3: Don't check FUSE_STRAP register for pipe c disabled Cc: Damien Lespiau Signed-off-by: Patrik Jakobsson Reviewed-by: Damien Lespiau [Jani: fixed some checkpatch indentation complaints] Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1453300280-10661-1-git-send-email-patrik.jakobsson@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index db9b0c6..4e3c741 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -809,6 +809,37 @@ static void intel_device_info_runtime_init(struct drm_device *dev) DRM_INFO("Display fused off, disabling\n"); info->num_pipes = 0; } + } else if (info->num_pipes > 0 && INTEL_INFO(dev)->gen == 9) { + u32 dfsm = I915_READ(SKL_DFSM); + u8 disabled_mask = 0; + bool invalid; + int num_bits; + + if (dfsm & SKL_DFSM_PIPE_A_DISABLE) + disabled_mask |= BIT(PIPE_A); + if (dfsm & SKL_DFSM_PIPE_B_DISABLE) + disabled_mask |= BIT(PIPE_B); + if (dfsm & SKL_DFSM_PIPE_C_DISABLE) + disabled_mask |= BIT(PIPE_C); + + num_bits = hweight8(disabled_mask); + + switch (disabled_mask) { + case BIT(PIPE_A): + case BIT(PIPE_B): + case BIT(PIPE_A) | BIT(PIPE_B): + case BIT(PIPE_A) | BIT(PIPE_C): + invalid = true; + break; + default: + invalid = false; + } + + if (num_bits > info->num_pipes || invalid) + DRM_ERROR("invalid pipe fuse configuration: 0x%x\n", + disabled_mask); + else + info->num_pipes -= num_bits; } /* Initialize slice/subslice/EU info */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 65e32a3..c0bd691 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5994,6 +5994,9 @@ enum skl_disp_power_wells { #define SKL_DFSM_CDCLK_LIMIT_540 (1 << 23) #define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23) #define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23) +#define SKL_DFSM_PIPE_A_DISABLE (1 << 30) +#define SKL_DFSM_PIPE_B_DISABLE (1 << 21) +#define SKL_DFSM_PIPE_C_DISABLE (1 << 28) #define GEN7_FF_SLICE_CS_CHICKEN1 _MMIO(0x20e0) #define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1<<14) -- cgit v0.10.2 From 985dd4360fdf2533fe48a33a4a2094f2e4718dc0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 28 Jan 2016 16:04:12 +0200 Subject: drm/i915/bxt: update list of PCIIDs Add PCIIDs for new versions of the SOC, based on BSpec. Also add the name of the versions as code comment where this is available. The new versions don't have any changes visible to the kernel driver. Signed-off-by: Imre Deak Reviewed-by: Mika Kuoppala Link: http://patchwork.freedesktop.org/patch/msgid/1453989852-13569-1-git-send-email-imre.deak@intel.com diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index f970209..9b48ac1 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -296,7 +296,9 @@ #define INTEL_BXT_IDS(info) \ INTEL_VGA_DEVICE(0x0A84, info), \ INTEL_VGA_DEVICE(0x1A84, info), \ - INTEL_VGA_DEVICE(0x5A84, info) + INTEL_VGA_DEVICE(0x1A85, info), \ + INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \ + INTEL_VGA_DEVICE(0x5A85, info) /* APL HD Graphics 500 */ #define INTEL_KBL_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \ -- cgit v0.10.2 From d81a67cc1bfdc3efed8590ee4e07a40b198908ba Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 29 Jan 2016 14:52:26 +0200 Subject: drm/i915: Sanity check DP AUX message buffer and size While we are calling intel_dp_aux_transfer() with msg->size=0 whenever msg->buffer is NULL, passing NULL to memcpy() is undefined according to the ISO C standard. I haven't found any notes about this in the GNU C's or the kernel's documentation of the function and can't imagine what it would do with the NULL ptr. To better document this use of the parameters it still make sense to add an explicit check for this to the code. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1454071949-24677-1-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f44aba1..a073f04 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -979,7 +979,10 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) if (WARN_ON(txsize > 20)) return -E2BIG; - memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size); + if (msg->buffer) + memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size); + else + WARN_ON(msg->size); ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize); if (ret > 0) { -- cgit v0.10.2 From 9c06f6744d663205395f88d98aef87edcd3ce5bd Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 29 Jan 2016 14:52:27 +0200 Subject: drm/i915/chv: Fix error path in GPU freq helpers Atm we wouldn't catch these errors or on the error path we would end up with a division-by-zero, fix this up. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1454071949-24677-2-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 31bc4ea..a47b8f2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7185,9 +7185,10 @@ static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val) { int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); - div = vlv_gpu_freq_div(czclk_freq) / 2; + div = vlv_gpu_freq_div(czclk_freq); if (div < 0) return div; + div /= 2; return DIV_ROUND_CLOSEST(czclk_freq * val, 2 * div) / 2; } @@ -7196,9 +7197,10 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val) { int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); - mul = vlv_gpu_freq_div(czclk_freq) / 2; + mul = vlv_gpu_freq_div(czclk_freq); if (mul < 0) return mul; + mul /= 2; /* CHV needs even values */ return DIV_ROUND_CLOSEST(val * 2 * mul, czclk_freq) * 2; -- cgit v0.10.2 From b074eae12f1e9f8eb1aafa3d7b922427f9b8e68a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 29 Jan 2016 14:52:28 +0200 Subject: drm/i915: Add debug info for failed MSI enabling While not being able to enable MSI interrupts may be a normal circumstance, for debugging it may still be a useful information, so emit an info about this. Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1454071949-24677-3-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4e3c741..a42eb58 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1109,8 +1109,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) * be lost or delayed, but we use them anyways to avoid * stuck interrupts on some machines. */ - if (!IS_I945G(dev) && !IS_I945GM(dev)) - pci_enable_msi(dev->pdev); + if (!IS_I945G(dev) && !IS_I945GM(dev)) { + if (pci_enable_msi(dev->pdev) < 0) + DRM_DEBUG_DRIVER("can't enable MSI"); + } intel_device_info_runtime_init(dev); -- cgit v0.10.2 From 05d25214c4d1cab99d1056f99b7e7d95e9e31ed0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 29 Jan 2016 14:52:29 +0200 Subject: drm/i915: Properly terminate KMS mode name string during tv init Signed-off-by: Imre Deak Reviewed-by: David Weinehall Link: http://patchwork.freedesktop.org/patch/msgid/1454071949-24677-4-git-send-email-imre.deak@intel.com diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 948cbff..5034b00 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1420,6 +1420,7 @@ intel_tv_get_modes(struct drm_connector *connector) if (!mode_ptr) continue; strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); + mode_ptr->name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; mode_ptr->hdisplay = hactive_s; mode_ptr->hsync_start = hactive_s + 1; -- cgit v0.10.2 From e1ea07542352be468e901173c7a1beeee404d696 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 6 Jan 2016 09:53:41 -0800 Subject: drm/i915/bxt: Don't save/restore eDP panel power during suspend (v3) Our attempts save/restore panel power state in i915_suspend.c are causing unclaimed register warnings on BXT since the registers for this platform differ from older platforms. The big hammer suspend/resume shouldn't be necessary for PP since the connector/encoder hooks should already handle this. In theory we could remove this for all platforms, but in practice it's likely that would cause some regressions since older platforms with LVDS may have incomplete PP handling. For now we'll leave the PCH save/restore alone and change the non-PCH branch to only operate on gen <= 4 so that BXT and future platforms aren't included. v2: Typo fix: s/||/&&/ v3: Change non-PCH condition to a gen <= 4 test rather than listing VLV/CHV/BXT as specific platforms to exclude; should be more future-proof as we add new platforms. (Daniel) Cc: Vandana Kannan Cc: Jani Nikula Cc: Daniel Vetter Cc: drm-intel-fixes@lists.freedesktop.org Signed-off-by: Matt Roper Reviewed-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1452102821-17190-1-git-send-email-matthew.d.roper@intel.com diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 6c6bedf..34e061a 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -49,7 +49,7 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); - } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { + } else if (INTEL_INFO(dev)->gen <= 4) { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); @@ -84,7 +84,7 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL); - } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { + } else if (INTEL_INFO(dev)->gen <= 4) { I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); -- cgit v0.10.2 From ed8d60f450d3db4c4dbb25eddc8f106cbab4bd1c Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 28 Jan 2016 15:09:37 -0800 Subject: drm/i915: Check DDI max lanes after applying BXT workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit bfb9faab8 we added a workaround for some BXT BIOS that fail to properly initialize the DDI_A_4_LANES bit of the control register (4 lanes is the only valid configuration on BXT since there is no DDI E to share with). A recent patch added some additional checks on this register bit before the workaround gets applied; this breaks eDP on BXT in some settings. Some minor code shuffling is all we need to restore the workaround. Cc: Ville Syrjälä Fixes: 7cd87cb80 ("drm/i915: Check max number of lanes when registering DDI ports") Signed-off-by: Matt Roper Link: http://patchwork.freedesktop.org/patch/msgid/1454022577-834-1-git-send-email-matthew.d.roper@intel.com Reviewed-by: Ville Syrjälä diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1f9a368..6d5b09f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -3281,7 +3281,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES); - intel_dig_port->max_lanes = max_lanes; /* * Bspec says that DDI_A_4_LANES is the only supported configuration @@ -3294,9 +3293,12 @@ void intel_ddi_init(struct drm_device *dev, enum port port) if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) { DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n"); intel_dig_port->saved_port_bits |= DDI_A_4_LANES; + max_lanes = 4; } } + intel_dig_port->max_lanes = max_lanes; + intel_encoder->type = INTEL_OUTPUT_UNKNOWN; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = 0; -- cgit v0.10.2 From b2435692dbb709d4c8ff3b2f2815c9b8423b72bb Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Tue, 2 Feb 2016 22:06:51 -0800 Subject: drm/i915: Pretend cursor is always on for ILK-style WM calculations (v2) Due to our lack of two-step watermark programming, our driver has historically pretended that the cursor plane is always on for the purpose of watermark calculations; this helps avoid serious flickering when the cursor turns off/on (e.g., when the user moves the mouse pointer to a different screen). That workaround was accidentally dropped as we started working toward atomic watermark updates. Since we still aren't quite there yet with two-stage updates, we need to resurrect the workaround and treat the cursor as always active. v2: Tweak cursor width calculations slightly to more closely match the logic we used before the atomic overhaul began. (Ville) Cc: simdev11@outlook.com Cc: manfred.kitzbichler@gmail.com Cc: drm-intel-fixes@lists.freedesktop.org Reported-by: simdev11@outlook.com Reported-by: manfred.kitzbichler@gmail.com Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93892 Fixes: 43d59eda1 ("drm/i915: Eliminate usage of plane_wm_parameters from ILK-style WM code (v2)") Signed-off-by: Matt Roper Link: http://patchwork.freedesktop.org/patch/msgid/1454479611-6804-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 a47b8f2..3da7935 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1799,16 +1799,20 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value) { - int cpp = pstate->base.fb ? - drm_format_plane_cpp(pstate->base.fb->pixel_format, 0) : 0; + /* + * We treat the cursor plane as always-on for the purposes of watermark + * calculation. Until we have two-stage watermark programming merged, + * this is necessary to avoid flickering. + */ + int cpp = 4; + int width = pstate->visible ? pstate->base.crtc_w : 64; - if (!cstate->base.active || !pstate->visible) + if (!cstate->base.active) return 0; return ilk_wm_method2(ilk_pipe_pixel_rate(cstate), cstate->base.adjusted_mode.crtc_htotal, - drm_rect_width(&pstate->dst), - cpp, mem_value); + width, cpp, mem_value); } /* Only for WM_LP. */ -- cgit v0.10.2 From de4726649b6b1d7f3f02b2031ee99e067cb71e2d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Jan 2016 18:32:31 +0000 Subject: drm/i915: Allow i915_gem_object_get_page() on userptr as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 033908aed5a596f6202c848c6bbc8a40fb1a8490 Author: Dave Gordon Date: Thu Dec 10 18:51:23 2015 +0000 drm/i915: mark GEM object pages dirty when mapped & written by the CPU introduced a check into i915_gem_object_get_dirty_pages() that returned a NULL pointer when called with a bad object, one that was not backed by shmemfs. This WARN was too strict as we can work on all struct page backed objects, and resulted in a WARN + GPF for existing userspace. In order to differentiate the various types of objects, add a new flags field to the i915_gem_object_ops struct to describe their capabilities, with the first flag being whether the object has struct pages. v2: Drop silly const before an integer in the structure declaration. Testcase: igt/gem_userptr_blits/relocations Reported-and-tested-by: Kristian Høgsberg Kristensen Signed-off-by: Chris Wilson Cc: Dave Gordon Cc: Kristian Høgsberg Kristensen Cc: Daniel Vetter Reviewed-by: Dave Gordon Reviewed-by: Kristian Høgsberg Kristensen Tested-by: Michal Winiarski Signed-off-by: Rodrigo Vivi Link: http://patchwork.freedesktop.org/patch/msgid/1453487551-16799-1-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 65a2cd0..77227a3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2038,6 +2038,9 @@ enum hdmi_force_audio { #define I915_GTT_OFFSET_NONE ((u32)-1) struct drm_i915_gem_object_ops { + unsigned int flags; +#define I915_GEM_OBJECT_HAS_STRUCT_PAGE 0x1 + /* Interface between the GEM object and its backing storage. * get_pages() is called once prior to the use of the associated set * of pages before to binding them into the GTT, and put_pages() is @@ -2053,6 +2056,7 @@ struct drm_i915_gem_object_ops { */ int (*get_pages)(struct drm_i915_gem_object *); void (*put_pages)(struct drm_i915_gem_object *); + int (*dmabuf_export)(struct drm_i915_gem_object *); void (*release)(struct drm_i915_gem_object *); }; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a928823..e9b19bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4465,6 +4465,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, } static const struct drm_i915_gem_object_ops i915_gem_object_ops = { + .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE, .get_pages = i915_gem_object_get_pages_gtt, .put_pages = i915_gem_object_put_pages_gtt, }; @@ -5309,7 +5310,7 @@ i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n) struct page *page; /* Only default objects have per-page dirty tracking */ - if (WARN_ON(obj->ops != &i915_gem_object_ops)) + if (WARN_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0)) return NULL; page = i915_gem_object_get_page(obj, n); diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 74a4d17..7107f2f 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -708,9 +708,10 @@ i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj) } static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = { - .dmabuf_export = i915_gem_userptr_dmabuf_export, + .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE, .get_pages = i915_gem_userptr_get_pages, .put_pages = i915_gem_userptr_put_pages, + .dmabuf_export = i915_gem_userptr_dmabuf_export, .release = i915_gem_userptr_release, }; -- cgit v0.10.2 From 58d4d32f431a560baff5fbb6deae8ad324552dde Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Wed, 3 Feb 2016 18:20:46 +0530 Subject: drm/i915/dsi: Configure DSI after enabling DSI pll We need to enable DSI PLL before configuring the DSI registers. This has worked before on BYT/CHV, but BXT is more fussy. Signed-off-by: Ramalingam C Reviewed-by: Mika Kahola Tested-by: Mika Kahola # BXT Tested-by: Jani Nikula # BYT Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454503846-12103-1-git-send-email-ramalingam.c@intel.com diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 91cef35..378f879 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -478,8 +478,8 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - intel_dsi_prepare(encoder); intel_enable_dsi_pll(encoder); + intel_dsi_prepare(encoder); /* Panel Enable over CRC PMIC */ if (intel_dsi->gpio_panel) -- cgit v0.10.2 From d5165ebd527c54bbe3761fd5810dede32b5246a3 Mon Sep 17 00:00:00 2001 From: Tim Gore Date: Thu, 4 Feb 2016 11:49:34 +0000 Subject: drm/i915: implement WaIncreaseDefaultTLBEntries WaIncreaseDefaultTLBEntries increases the number of TLB entries available for GPGPU workloads and gives significant ( > 10% ) performance gain for some OCL benchmarks. Put this in a new function that can be a place for workarounds that are GT related but not required per ring. This function is called on driver load and also after a reset and on resume, so it is safe for workarounds that get clobbered in these situations. This function currently has just this one workaround. v2: This was originally split into 3 patches but following review feedback was squashed into 1. I have not incorporated some style comments from Chris Wilson as I felt that after defining and intialising a temporary variable and then adding an additional if block to only write the register if the temporary variable had been set, this didn't really give a net gain. v3: Resending in the hope that BAT will run v4: Change subject line to trigger BAT (please!) Signed-off-by: Tim Gore Reviewed-by: Mika Kuoppala Signed-off-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1454586574-2343-1-git-send-email-tim.gore@intel.com diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 715a771..9127f8f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2132,6 +2132,25 @@ static void i915_address_space_init(struct i915_address_space *vm, list_add_tail(&vm->global_link, &dev_priv->vm_list); } +static void gtt_write_workarounds(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* This function is for gtt related workarounds. This function is + * called on driver load and after a GPU reset, so you can place + * workarounds here even if they get overwritten by GPU reset. + */ + /* WaIncreaseDefaultTLBEntries:chv,bdw,skl,bxt */ + if (IS_BROADWELL(dev)) + I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_BDW); + else if (IS_CHERRYVIEW(dev)) + I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_CHV); + else if (IS_SKYLAKE(dev)) + I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_SKL); + else if (IS_BROXTON(dev)) + I915_WRITE(GEN8_L3_LRA_1_GPGPU, GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT); +} + int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2148,6 +2167,8 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) int i915_ppgtt_init_hw(struct drm_device *dev) { + gtt_write_workarounds(dev); + /* In the case of execlists, PPGTT is enabled by the context descriptor * and the PDPs are contained within the context itself. We don't * need to do anything here. */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c0bd691..ec6444a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8173,4 +8173,11 @@ enum skl_disp_power_wells { #define GEN9_VEBOX_MOCS(i) _MMIO(0xcb00 + (i) * 4) /* Video MOCS registers */ #define GEN9_BLT_MOCS(i) _MMIO(0xcc00 + (i) * 4) /* Blitter MOCS registers */ +/* gamt regs */ +#define GEN8_L3_LRA_1_GPGPU _MMIO(0x4dd4) +#define GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_BDW 0x67F1427F /* max/min for LRA1/2 */ +#define GEN8_L3_LRA_1_GPGPU_DEFAULT_VALUE_CHV 0x5FF101FF /* max/min for LRA1/2 */ +#define GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_SKL 0x67F1427F /* " " */ +#define GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT 0x5FF101FF /* " " */ + #endif /* _I915_REG_H_ */ -- cgit v0.10.2 From 3eb7c38bfed5dc6ea0e24c8bc2fd249760bdde8c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 29 Jan 2016 18:57:38 -0200 Subject: drm/i915: don't deactivate FBC at skylake_disable_primary_plane FBC is already deactivated at this point. Besides, nothing should be calling these lower-level function pointers. A few months ago, the only caller of dev_priv->fbc.deactivate was intel_pipe_set_base_atomic(), which was the kgdboc function. But the following commit added it to the SKL function: commit a8d201af68506b375b701d0d8dbe8487034256f2 Author: Maarten Lankhorst Date: Thu Jan 7 11:54:11 2016 +0100 drm/i915: Use plane state for primary plane updates. Cc: Maarten Lankhorst Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1454101060-23198-1-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a66220a..186d6ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3156,9 +3156,6 @@ static void skylake_disable_primary_plane(struct drm_plane *primary, struct drm_i915_private *dev_priv = dev->dev_private; int pipe = to_intel_crtc(crtc)->pipe; - if (dev_priv->fbc.deactivate) - dev_priv->fbc.deactivate(dev_priv); - I915_WRITE(PLANE_CTL(pipe, 0), 0); I915_WRITE(PLANE_SURF(pipe, 0), 0); POSTING_READ(PLANE_SURF(pipe, 0)); -- cgit v0.10.2 From 8c40074cb219f8e5e6122d17fad869bc43c3e9df Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 29 Jan 2016 18:57:39 -0200 Subject: drm/i915/fbc: unexport the HW level activation functions The recent introduction of a new caller of dev_priv->fbc.deactivate() is a good example of why we need unexport those functions. Anything outside intel_fbc.c should only call the functions exported by intel_fbc.c, so in order to enforce that, kill the function pointers stored inside dev_priv->fbc and replace them with functions that can't be called from outside intel_fbc.c. This should make it much harder for new code to call these functions from outside intel_fbc.c. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1454101060-23198-2-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 77227a3..856bfe8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -964,10 +964,6 @@ struct intel_fbc { } work; const char *no_fbc_reason; - - bool (*is_active)(struct drm_i915_private *dev_priv); - void (*activate)(struct drm_i915_private *dev_priv); - void (*deactivate)(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 5adf6d7..8d3caf2 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -43,7 +43,7 @@ static inline bool fbc_supported(struct drm_i915_private *dev_priv) { - return dev_priv->fbc.activate != NULL; + return HAS_FBC(dev_priv); } static inline bool fbc_on_pipe_a_only(struct drm_i915_private *dev_priv) @@ -343,6 +343,38 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) intel_fbc_recompress(dev_priv); } +static bool intel_fbc_hw_is_active(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv)->gen >= 5) + return ilk_fbc_is_active(dev_priv); + else if (IS_GM45(dev_priv)) + return g4x_fbc_is_active(dev_priv); + else + return i8xx_fbc_is_active(dev_priv); +} + +static void intel_fbc_hw_activate(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv)->gen >= 7) + gen7_fbc_activate(dev_priv); + else if (INTEL_INFO(dev_priv)->gen >= 5) + ilk_fbc_activate(dev_priv); + else if (IS_GM45(dev_priv)) + g4x_fbc_activate(dev_priv); + else + i8xx_fbc_activate(dev_priv); +} + +static void intel_fbc_hw_deactivate(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv)->gen >= 5) + ilk_fbc_deactivate(dev_priv); + else if (IS_GM45(dev_priv)) + g4x_fbc_deactivate(dev_priv); + else + i8xx_fbc_deactivate(dev_priv); +} + /** * intel_fbc_is_active - Is FBC active? * @dev_priv: i915 device instance @@ -405,7 +437,7 @@ retry: goto retry; } - fbc->activate(dev_priv); + intel_fbc_hw_activate(dev_priv); work->scheduled = false; @@ -451,7 +483,7 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) fbc->work.scheduled = false; if (fbc->active) - fbc->deactivate(dev_priv); + intel_fbc_hw_deactivate(dev_priv); } static bool multiple_pipes_ok(struct intel_crtc *crtc) @@ -713,7 +745,7 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc) /* FIXME: We lack the proper locking here, so only run this on the * platforms that need. */ - if (dev_priv->fbc.activate == ilk_fbc_activate) + if (INTEL_INFO(dev_priv)->gen >= 5 && INTEL_INFO(dev_priv)->gen < 7) cache->fb.ilk_ggtt_offset = i915_gem_obj_ggtt_offset(obj); cache->fb.pixel_format = fb->pixel_format; cache->fb.stride = fb->pitches[0]; @@ -1223,30 +1255,13 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) break; } - if (INTEL_INFO(dev_priv)->gen >= 7) { - fbc->is_active = ilk_fbc_is_active; - fbc->activate = gen7_fbc_activate; - fbc->deactivate = ilk_fbc_deactivate; - } else if (INTEL_INFO(dev_priv)->gen >= 5) { - fbc->is_active = ilk_fbc_is_active; - fbc->activate = ilk_fbc_activate; - fbc->deactivate = ilk_fbc_deactivate; - } else if (IS_GM45(dev_priv)) { - fbc->is_active = g4x_fbc_is_active; - fbc->activate = g4x_fbc_activate; - fbc->deactivate = g4x_fbc_deactivate; - } else { - fbc->is_active = i8xx_fbc_is_active; - fbc->activate = i8xx_fbc_activate; - fbc->deactivate = i8xx_fbc_deactivate; - - /* This value was pulled out of someone's hat */ + /* This value was pulled out of someone's hat */ + if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_GM45(dev_priv)) I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); - } /* We still don't have any sort of hardware state readout for FBC, so * deactivate it in case the BIOS activated it to make sure software * matches the hardware state. */ - if (fbc->is_active(dev_priv)) - fbc->deactivate(dev_priv); + if (intel_fbc_hw_is_active(dev_priv)) + intel_fbc_hw_deactivate(dev_priv); } -- cgit v0.10.2 From 5375ce9f38291c1d725db40519465dfe89c60ea9 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 29 Jan 2016 18:57:40 -0200 Subject: drm/i915/fbc: set fbc->active from the new activation functions Now that we have top-level gen-independent hw_activate and hw_deactivate functions, set fbc->active directly from them, removing the duplicated code. Reviewed-by: Maarten Lankhorst Signed-off-by: Paulo Zanoni Link: http://patchwork.freedesktop.org/patch/msgid/1454101060-23198-3-git-send-email-paulo.r.zanoni@intel.com diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 8d3caf2..3614a95 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -115,8 +115,6 @@ static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv) { u32 fbc_ctl; - dev_priv->fbc.active = false; - /* Disable compression */ fbc_ctl = I915_READ(FBC_CONTROL); if ((fbc_ctl & FBC_CTL_EN) == 0) @@ -139,8 +137,6 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) int i; u32 fbc_ctl; - dev_priv->fbc.active = true; - /* Note: fbc.threshold == 1 for i8xx */ cfb_pitch = params->cfb_size / FBC_LL_SIZE; if (params->fb.stride < cfb_pitch) @@ -187,8 +183,6 @@ static void g4x_fbc_activate(struct drm_i915_private *dev_priv) struct intel_fbc_reg_params *params = &dev_priv->fbc.params; u32 dpfc_ctl; - dev_priv->fbc.active = true; - dpfc_ctl = DPFC_CTL_PLANE(params->crtc.plane) | DPFC_SR_EN; if (drm_format_plane_cpp(params->fb.pixel_format, 0) == 2) dpfc_ctl |= DPFC_CTL_LIMIT_2X; @@ -206,8 +200,6 @@ static void g4x_fbc_deactivate(struct drm_i915_private *dev_priv) { u32 dpfc_ctl; - dev_priv->fbc.active = false; - /* Disable compression */ dpfc_ctl = I915_READ(DPFC_CONTROL); if (dpfc_ctl & DPFC_CTL_EN) { @@ -234,8 +226,6 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv) u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; - dev_priv->fbc.active = true; - dpfc_ctl = DPFC_CTL_PLANE(params->crtc.plane); if (drm_format_plane_cpp(params->fb.pixel_format, 0) == 2) threshold++; @@ -274,8 +264,6 @@ static void ilk_fbc_deactivate(struct drm_i915_private *dev_priv) { u32 dpfc_ctl; - dev_priv->fbc.active = false; - /* Disable compression */ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); if (dpfc_ctl & DPFC_CTL_EN) { @@ -295,8 +283,6 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; - dev_priv->fbc.active = true; - dpfc_ctl = 0; if (IS_IVYBRIDGE(dev_priv)) dpfc_ctl |= IVB_DPFC_CTL_PLANE(params->crtc.plane); @@ -355,6 +341,10 @@ static bool intel_fbc_hw_is_active(struct drm_i915_private *dev_priv) static void intel_fbc_hw_activate(struct drm_i915_private *dev_priv) { + struct intel_fbc *fbc = &dev_priv->fbc; + + fbc->active = true; + if (INTEL_INFO(dev_priv)->gen >= 7) gen7_fbc_activate(dev_priv); else if (INTEL_INFO(dev_priv)->gen >= 5) @@ -367,6 +357,10 @@ static void intel_fbc_hw_activate(struct drm_i915_private *dev_priv) static void intel_fbc_hw_deactivate(struct drm_i915_private *dev_priv) { + struct intel_fbc *fbc = &dev_priv->fbc; + + fbc->active = false; + if (INTEL_INFO(dev_priv)->gen >= 5) ilk_fbc_deactivate(dev_priv); else if (IS_GM45(dev_priv)) -- cgit v0.10.2 From 5d2d0a12d3d08bf50434f0b5947bb73bac04b941 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Feb 2016 12:50:49 +0200 Subject: drm/i915/dsi: defend gpio table against out of bounds access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not blindly trust the VBT data used for indexing. Cc: stable@vger.kernel.org Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/cc32d40c2b47f2d2151811855ac2c3dabab1d57d.1454582914.git.jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 1d43e6f..4775aa5 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -209,6 +209,11 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) /* pull up/down */ action = *data++; + if (gpio >= ARRAY_SIZE(gtable)) { + DRM_DEBUG_KMS("unknown gpio %u\n", gpio); + goto out; + } + function = gtable[gpio].function_reg; pad = gtable[gpio].pad_reg; @@ -226,6 +231,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) vlv_gpio_nc_write(dev_priv, pad, val); mutex_unlock(&dev_priv->sb_lock); +out: return data; } -- cgit v0.10.2 From 4e1c63e3761b84ec7d87c75b58bbc8bcf18e98ee Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Feb 2016 12:50:50 +0200 Subject: drm/i915/dsi: don't pass arbitrary data to sideband MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since sequence block v2 the second byte contains flags other than just pull up/down. Don't pass arbitrary data to the sideband interface. The rest may or may not work for sequence block v2, but there should be no harm done. Cc: stable@vger.kernel.org Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/ebe3c2eee623afc4b3a134533b01f8d591d13f32.1454582914.git.jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 4775aa5..6f013ef 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -207,7 +207,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) gpio = *data++; /* pull up/down */ - action = *data++; + action = *data++ & 1; if (gpio >= ARRAY_SIZE(gtable)) { DRM_DEBUG_KMS("unknown gpio %u\n", gpio); -- cgit v0.10.2 From 4688d45f97f215447d552ff5bc960072e865e0ff Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Feb 2016 12:50:53 +0200 Subject: drm/i915: put the IOSF port defines in numerical order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it easier to spot duplicates. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/a89f10d2d1954ac1b9a278534cb5209973354caa.1454582914.git.jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ec6444a..85d56ad 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -610,16 +610,16 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define IOSF_BYTE_ENABLES_SHIFT 4 #define IOSF_BAR_SHIFT 1 #define IOSF_SB_BUSY (1<<0) -#define IOSF_PORT_BUNIT 0x3 -#define IOSF_PORT_PUNIT 0x4 +#define IOSF_PORT_BUNIT 0x03 +#define IOSF_PORT_PUNIT 0x04 #define IOSF_PORT_NC 0x11 #define IOSF_PORT_DPIO 0x12 -#define IOSF_PORT_DPIO_2 0x1a #define IOSF_PORT_GPIO_NC 0x13 #define IOSF_PORT_CCK 0x14 -#define IOSF_PORT_CCU 0xA9 +#define IOSF_PORT_DPIO_2 0x1a +#define IOSF_PORT_FLISDSI 0x1b #define IOSF_PORT_GPS_CORE 0x48 -#define IOSF_PORT_FLISDSI 0x1B +#define IOSF_PORT_CCU 0xa9 #define VLV_IOSF_DATA _MMIO(VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR _MMIO(VLV_DISPLAY_BASE + 0x2108) -- cgit v0.10.2 From 10182e77f52f1f703c9e5fea3656446aa850ebda Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Feb 2016 12:50:54 +0200 Subject: drm/i915/vlv: drop unused vlv_gps_core_read/write functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/532150999335216b1374c606e1b3c253a6c9fe9d.1454582914.git.jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 856bfe8..bd126ff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3479,8 +3479,6 @@ u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); -u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg); -void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg); void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val); u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 85d56ad..6867295 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -618,7 +618,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define IOSF_PORT_CCK 0x14 #define IOSF_PORT_DPIO_2 0x1a #define IOSF_PORT_FLISDSI 0x1b -#define IOSF_PORT_GPS_CORE 0x48 #define IOSF_PORT_CCU 0xa9 #define VLV_IOSF_DATA _MMIO(VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR _MMIO(VLV_DISPLAY_BASE + 0x2108) diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 8831fc5..f5b0ab6 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -171,20 +171,6 @@ void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) SB_CRWRDA_NP, reg, &val); } -u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg) -{ - u32 val = 0; - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE, - SB_CRRDDA_NP, reg, &val); - return val; -} - -void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) -{ - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE, - SB_CRWRDA_NP, reg, &val); -} - u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = 0; -- cgit v0.10.2 From dfb19ed20c322616a73b212c96f2e0309e35cd1a Mon Sep 17 00:00:00 2001 From: Deepak M Date: Thu, 4 Feb 2016 18:55:15 +0200 Subject: drm/i915: Extend gpio read/write to other cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the gpio read/write functions more generic iosf sideband read/write functions, taking the iosf port as argument. v2: rebase v3: rebase v4 by Jani: address Ville's review v5 by Jani: drop the PCI_DEVFN change (Ville) Signed-off-by: Deepak M Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454604915-17142-1-git-send-email-jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bd126ff..8216665 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3471,8 +3471,8 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr); void vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val); u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr); -u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg); -void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); +u32 vlv_iosf_sb_read(struct drm_i915_private *dev_priv, u8 port, u32 reg); +void vlv_iosf_sb_write(struct drm_i915_private *dev_priv, u8 port, u32 reg, u32 val); u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6867295..6732fc1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -618,6 +618,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define IOSF_PORT_CCK 0x14 #define IOSF_PORT_DPIO_2 0x1a #define IOSF_PORT_FLISDSI 0x1b +#define IOSF_PORT_GPIO_SC 0x48 +#define IOSF_PORT_GPIO_SUS 0xa8 #define IOSF_PORT_CCU 0xa9 #define VLV_IOSF_DATA _MMIO(VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR _MMIO(VLV_DISPLAY_BASE + 0x2108) diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 6f013ef..76dbd1a 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -221,14 +221,15 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) if (!gtable[gpio].init) { /* program the function */ /* FIXME: remove constant below */ - vlv_gpio_nc_write(dev_priv, function, 0x2000CC00); + vlv_iosf_sb_write(dev_priv, IOSF_PORT_GPIO_NC, function, + 0x2000CC00); gtable[gpio].init = 1; } val = 0x4 | action; /* pull up/down */ - vlv_gpio_nc_write(dev_priv, pad, val); + vlv_iosf_sb_write(dev_priv, IOSF_PORT_GPIO_NC, pad, val); mutex_unlock(&dev_priv->sb_lock); out: diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index f5b0ab6..c399818 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -129,17 +129,18 @@ u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) return val; } -u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg) +u32 vlv_iosf_sb_read(struct drm_i915_private *dev_priv, u8 port, u32 reg) { u32 val = 0; - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC, + vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), port, SB_CRRDDA_NP, reg, &val); return val; } -void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +void vlv_iosf_sb_write(struct drm_i915_private *dev_priv, + u8 port, u32 reg, u32 val) { - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC, + vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), port, SB_CRWRDA_NP, reg, &val); } -- cgit v0.10.2 From 96afef1d5adee8722549c8c2b788d656ea2ecf21 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Feb 2016 18:52:47 +0200 Subject: drm/i915/dsi: skip gpio element execution when not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip v3 gpio element because the support is not there, and skip gpio element on non-vlv because the sideband code is vlv specific. v2: the gpio stuff is currently only supported on vlv (Ville) Cc: drm-intel-fixes@lists.freedesktop.org Fixes: 2a33d93486f2 ("drm/i915/bios: add support for MIPI sequence block v3") Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454604767-2440-1-git-send-email-jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 76dbd1a..787f01c 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -204,6 +204,9 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) struct drm_device *dev = intel_dsi->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->vbt.dsi.seq_version >= 3) + data++; + gpio = *data++; /* pull up/down */ @@ -214,6 +217,16 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) goto out; } + if (!IS_VALLEYVIEW(dev_priv)) { + DRM_DEBUG_KMS("GPIO element not supported on this platform\n"); + goto out; + } + + if (dev_priv->vbt.dsi.seq_version >= 3) { + DRM_DEBUG_KMS("GPIO element v3 not supported\n"); + goto out; + } + function = gtable[gpio].function_reg; pad = gtable[gpio].pad_reg; -- cgit v0.10.2 From 23a5110dc619073b57d90c36eae383f51df03aac Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Feb 2016 12:16:09 +0200 Subject: drm/i915/dp: abstract training pattern selection Make it cleaner to add more checks in the function. No functional changes. Cc: Ander Conselvan de Oliveira Cc: Sivakumar Thulasimani Reviewed-by: Sivakumar Thulasimani Cc: drm-intel-fixes@lists.freedesktop.org # dependency on the next patch Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454667370-8001-1-git-send-email-jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 8888793..83e667b 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -215,16 +215,15 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) } } -static void -intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) +/* + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2 + * or 1.2 devices that support it, Training Pattern 2 otherwise. + */ +static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) { - bool channel_eq = false; - int tries, cr_tries; - uint32_t training_pattern = DP_TRAINING_PATTERN_2; + u32 training_pattern = DP_TRAINING_PATTERN_2; /* - * Training Pattern 3 for HBR2 or 1.2 devices that support it. - * * Intel platforms that support HBR2 also support TPS3. TPS3 support is * also mandatory for downstream devices that support HBR2. * @@ -237,6 +236,18 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) else if (intel_dp->link_rate == 540000) DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n"); + return training_pattern; +} + +static void +intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) +{ + bool channel_eq = false; + int tries, cr_tries; + u32 training_pattern; + + training_pattern = intel_dp_training_pattern(intel_dp); + /* channel equalization */ if (!intel_dp_set_link_train(intel_dp, training_pattern | -- cgit v0.10.2 From bfcef5d2135ea1200ac1ea44661619ab8785c9f0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 5 Feb 2016 12:16:10 +0200 Subject: drm/i915/dp: reduce missing TPS3 support errors to debug logging Per spec, TPS3 support is mandatory for downstream devices that support HBR2. We've therefore logged errors on HBR2 without TPS3 since commit 1da7d7131c35cde83f1bab8ec732b57b69bef814 Author: Jani Nikula Date: Thu Sep 3 11:16:08 2015 +0300 drm/i915: ignore link rate in TPS3 selection However, it seems there are real world devices out there that just aren't spec compliant, and still work at HBR2 using TPS2. So reduce the error message to debug logging. Cc: Ander Conselvan de Oliveira Cc: Sivakumar Thulasimani Reviewed-by: Sivakumar Thulasimani Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92932 Fixes: 1da7d7131c35 ("drm/i915: ignore link rate in TPS3 selection") Cc: drm-intel-fixes@lists.freedesktop.org Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454667370-8001-2-git-send-email-jani.nikula@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 83e667b..0b8eefc 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -222,19 +222,27 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) { u32 training_pattern = DP_TRAINING_PATTERN_2; + bool source_tps3, sink_tps3; /* * Intel platforms that support HBR2 also support TPS3. TPS3 support is - * also mandatory for downstream devices that support HBR2. + * also mandatory for downstream devices that support HBR2. However, not + * all sinks follow the spec. * * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is - * supported but still not enabled. + * supported in source but still not enabled. */ - if (intel_dp_source_supports_hbr2(intel_dp) && - drm_dp_tps3_supported(intel_dp->dpcd)) + source_tps3 = intel_dp_source_supports_hbr2(intel_dp); + sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd); + + if (source_tps3 && sink_tps3) { training_pattern = DP_TRAINING_PATTERN_3; - else if (intel_dp->link_rate == 540000) - DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n"); + } else if (intel_dp->link_rate == 540000) { + if (!source_tps3) + DRM_DEBUG_KMS("5.4 Gbps link rate without source HBR2/TPS3 support\n"); + if (!sink_tps3) + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n"); + } return training_pattern; } -- cgit v0.10.2 From 274008e89d78ded4324c7d81d9d106f62f5d5727 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Sat, 6 Feb 2016 00:13:29 +0530 Subject: drm/i915/bxt: Check BIOS RC6 setup before enabling RC6 RC6 setup is shared between BIOS and Driver. BIOS sets up subset of RC6 setup registers. If those are not setup Driver should not enable RC6. For implementing this, driver can check RC_CTRL0 and RC_CTRL1 values to know if BIOS has enabled HW/SW RC6. This will also enable user to control RC6 using BIOS settings alone. RC6 related instability can be avoided by disabling via BIOS settings till driver fixes it. v2: Had placed logic in gen8 function by mistake. Fixed it. Ensuring RPM is not enabled in case BIOS disabled RC6. v3: Need to disable RPM if RC6 is disabled due to BIOS settings. (Daniel) Runtime PM enabling happens before gen9_enable_rc6. Moved the updation of enable_rc6 parameter in intel_uncore_sanitize. v4: Added elaborate check for BIOS RC6 setup. Prepared check_pctx for bxt. (Imre) v5: Caching reserved stolen base and size in the driver private data. Reorganized RC6 setup check. Moved from gen9_enable_rc6 to intel_uncore_sanitize. (Imre) v6: Rebasing on the patch submitted by Imre that moves gem_init_stolen earlier in the load. v7: Removed PWRCTX_MAXCNT_VCSUNIT1 check as it applies to SKL. (Imre) v8: Fixed formatting and checkpatch issues. Fixed functional issue where RC6 ctx size check was missing. (Imre) Cc: Imre Deak Signed-off-by: Sagar Arun Kamble Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1454697809-22113-1-git-send-email-sagar.a.kamble@intel.com diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f520c90..66a6da2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -342,6 +342,8 @@ struct i915_gtt { size_t stolen_size; /* Total size of stolen memory */ size_t stolen_usable_size; /* Total size minus BIOS reserved */ + size_t stolen_reserved_base; + size_t stolen_reserved_size; u64 mappable_end; /* End offset that we can CPU map */ struct io_mapping *mappable; /* Mapping to our CPU mappable region */ phys_addr_t mappable_base; /* PA of our GMADR */ diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index c384dc9..ba1a00d 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -458,6 +458,9 @@ int i915_gem_init_stolen(struct drm_device *dev) return 0; } + dev_priv->gtt.stolen_reserved_base = reserved_base; + dev_priv->gtt.stolen_reserved_size = reserved_size; + /* It is possible for the reserved area to end before the end of stolen * memory, so just consider the start. */ reserved_total = stolen_top - reserved_base; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6732fc1..188ad5d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6785,6 +6785,16 @@ enum skl_disp_power_wells { #define VLV_PMWGICZ _MMIO(0x1300a4) +#define RC6_LOCATION _MMIO(0xD40) +#define RC6_CTX_IN_DRAM (1 << 0) +#define RC6_CTX_BASE _MMIO(0xD48) +#define RC6_CTX_BASE_MASK 0xFFFFFFF0 +#define PWRCTX_MAXCNT_RCSUNIT _MMIO(0x2054) +#define PWRCTX_MAXCNT_VCSUNIT0 _MMIO(0x12054) +#define PWRCTX_MAXCNT_BCSUNIT _MMIO(0x22054) +#define PWRCTX_MAXCNT_VECSUNIT _MMIO(0x1A054) +#define PWRCTX_MAXCNT_VCSUNIT1 _MMIO(0x1C054) +#define IDLE_TIME_MASK 0xFFFFF #define FORCEWAKE _MMIO(0xA18C) #define FORCEWAKE_VLV _MMIO(0x1300b0) #define FORCEWAKE_ACK_VLV _MMIO(0x1300b4) @@ -6923,6 +6933,7 @@ enum skl_disp_power_wells { #define GEN6_RPDEUC _MMIO(0xA084) #define GEN6_RPDEUCSW _MMIO(0xA088) #define GEN6_RC_STATE _MMIO(0xA094) +#define RC6_STATE (1 << 18) #define GEN6_RC1_WAKE_RATE_LIMIT _MMIO(0xA098) #define GEN6_RC6_WAKE_RATE_LIMIT _MMIO(0xA09C) #define GEN6_RC6pp_WAKE_RATE_LIMIT _MMIO(0xA0A0) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 93ba14a..1251a7a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1566,6 +1566,7 @@ void skl_wm_get_hw_state(struct drm_device *dev); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb /* out */); uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config); +int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6); /* intel_sdvo.c */ bool intel_sdvo_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3da7935..379eabe 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4562,12 +4562,62 @@ static void intel_print_rc6_info(struct drm_device *dev, u32 mode) onoff(mode & GEN6_RC_CTL_RC6_ENABLE)); } -static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) +static bool bxt_check_bios_rc6_setup(const struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable_rc6 = true; + unsigned long rc6_ctx_base; + + if (!(I915_READ(RC6_LOCATION) & RC6_CTX_IN_DRAM)) { + DRM_DEBUG_KMS("RC6 Base location not set properly.\n"); + enable_rc6 = false; + } + + /* + * The exact context size is not known for BXT, so assume a page size + * for this check. + */ + rc6_ctx_base = I915_READ(RC6_CTX_BASE) & RC6_CTX_BASE_MASK; + if (!((rc6_ctx_base >= dev_priv->gtt.stolen_reserved_base) && + (rc6_ctx_base + PAGE_SIZE <= dev_priv->gtt.stolen_reserved_base + + dev_priv->gtt.stolen_reserved_size))) { + DRM_DEBUG_KMS("RC6 Base address not as expected.\n"); + enable_rc6 = false; + } + + if (!(((I915_READ(PWRCTX_MAXCNT_RCSUNIT) & IDLE_TIME_MASK) > 1) && + ((I915_READ(PWRCTX_MAXCNT_VCSUNIT0) & IDLE_TIME_MASK) > 1) && + ((I915_READ(PWRCTX_MAXCNT_BCSUNIT) & IDLE_TIME_MASK) > 1) && + ((I915_READ(PWRCTX_MAXCNT_VECSUNIT) & IDLE_TIME_MASK) > 1))) { + DRM_DEBUG_KMS("Engine Idle wait time not set properly.\n"); + enable_rc6 = false; + } + + if (!(I915_READ(GEN6_RC_CONTROL) & (GEN6_RC_CTL_RC6_ENABLE | + GEN6_RC_CTL_HW_ENABLE)) && + ((I915_READ(GEN6_RC_CONTROL) & GEN6_RC_CTL_HW_ENABLE) || + !(I915_READ(GEN6_RC_STATE) & RC6_STATE))) { + DRM_DEBUG_KMS("HW/SW RC6 is not enabled by BIOS.\n"); + enable_rc6 = false; + } + + return enable_rc6; +} + +int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) { /* No RC6 before Ironlake and code is gone for ilk. */ if (INTEL_INFO(dev)->gen < 6) return 0; + if (!enable_rc6) + return 0; + + if (IS_BROXTON(dev) && !bxt_check_bios_rc6_setup(dev)) { + DRM_INFO("RC6 disabled by BIOS\n"); + return 0; + } + /* Respect the kernel parameter if it is set */ if (enable_rc6 >= 0) { int mask; @@ -6057,7 +6107,6 @@ void intel_init_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6); /* * RPM depends on RC6 to save restore the GT HW context, so make RC6 a * requirement. diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index bfa79e5..436d8f2 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -400,6 +400,8 @@ void intel_uncore_early_sanitize(struct drm_device *dev, bool restore_forcewake) void intel_uncore_sanitize(struct drm_device *dev) { + i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6); + /* BIOS often leaves RC6 enabled, but disable it for hw init */ intel_disable_gt_powersave(dev); } -- cgit v0.10.2 From db168f117779b23097487548b4f4999b0a66835c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 3 Feb 2016 16:53:23 +0100 Subject: drm/i915: Remove intel_crtc->atomic.disable_ips. This is a revert of commit 066cf55b9ce3 "drm/i915: Fix IPS related flicker". intel_pre_disable_primary already handles this, and now everything goes through the atomic path there's no need to try to disable ips twice. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Link: http://patchwork.freedesktop.org/patch/msgid/1454514805-10595-2-git-send-email-maarten.lankhorst@linux.intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 186d6ca..4760ecb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4815,9 +4815,6 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->update_fbc) intel_fbc_pre_update(crtc); - if (crtc->atomic.disable_ips) - hsw_disable_ips(crtc); - if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); @@ -11889,18 +11886,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.post_enable_primary = turn_on; intel_crtc->atomic.update_fbc = true; - if (turn_off) { - /* - * FIXME: Actually if we will still have any other - * plane enabled on the pipe we could let IPS enabled - * still, but for now lets consider that when we make - * primary invisible by setting DSPCNTR to 0 on - * update_primary_plane function IPS needs to be - * disable. - */ - intel_crtc->atomic.disable_ips = true; - } - /* * BDW signals flip done immediately if the plane * is disabled, even if the plane enable is already diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1251a7a..5fd3e13 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -544,7 +544,6 @@ struct intel_mmio_flip { */ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ - bool disable_ips; bool pre_disable_primary; /* Sleepable operations to perform after commit */ -- cgit v0.10.2 From 5c74cd730807a6f0c4a2066bdb92c2b6fc3e5775 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 3 Feb 2016 16:53:24 +0100 Subject: drm/i915: Remove atomic.pre_disable_primary. This can be derived from the atomic state in pre_plane_update, which makes it more clear when it's supposed to be called. Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1454514805-10595-3-git-send-email-maarten.lankhorst@linux.intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4760ecb..a7fa627 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4804,19 +4804,33 @@ static void intel_post_plane_update(struct intel_crtc *crtc) memset(atomic, 0, sizeof(*atomic)); } -static void intel_pre_plane_update(struct intel_crtc *crtc) +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); struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->base.state); + struct drm_atomic_state *old_state = old_crtc_state->base.state; + struct drm_plane *primary = crtc->base.primary; + struct drm_plane_state *old_pri_state = + drm_atomic_get_existing_plane_state(old_state, primary); + bool modeset = needs_modeset(&pipe_config->base); if (atomic->update_fbc) intel_fbc_pre_update(crtc); - if (atomic->pre_disable_primary) - intel_pre_disable_primary(&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); + + if (old_primary_state->visible && + (modeset || !primary_state->visible)) + intel_pre_disable_primary(&crtc->base); + } if (pipe_config->disable_cxsr) { crtc->wm.cxsr_allowed = false; @@ -11882,7 +11896,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; intel_crtc->atomic.update_fbc = true; @@ -13494,7 +13507,7 @@ static int intel_atomic_commit(struct drm_device *dev, if (!needs_modeset(crtc->state)) continue; - intel_pre_plane_update(intel_crtc); + intel_pre_plane_update(to_intel_crtc_state(crtc_state)); if (crtc_state->active) { intel_crtc_disable_planes(crtc, crtc_state->plane_mask); @@ -13550,7 +13563,7 @@ static int intel_atomic_commit(struct drm_device *dev, } if (!modeset) - intel_pre_plane_update(intel_crtc); + intel_pre_plane_update(to_intel_crtc_state(crtc_state)); if (crtc->state->active && intel_crtc->atomic.update_fbc) intel_fbc_enable(intel_crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5fd3e13..d0921ba 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -544,7 +544,6 @@ struct intel_mmio_flip { */ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ - bool pre_disable_primary; /* Sleepable operations to perform after commit */ unsigned fb_bits; -- cgit v0.10.2 From 2dfd178dc05164d6d730f4b3649accc1ee1ee585 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 3 Feb 2016 16:53:25 +0100 Subject: drm/i915: Do not disable cxsr when crtc is disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's safe to assume cxsr is already disabled when the crtc is off. This prevents an unclaimed register warning when the required power wells are not enabled. [ 262.864984] ------------[ cut here ]------------ [ 262.865025] WARNING: CPU: 1 PID: 6799 at drivers/gpu/drm/i915/intel_uncore.c:638 __unclaimed_reg_debug+0x68/0x80 [i915]() [ 262.865029] Unclaimed register detected before reading register 0x186500 [ 262.865032] Modules linked in: i915 intel_powerclamp [ 262.865057] CPU: 1 PID: 6799 Comm: kms_pipe_crc_ba Tainted: G U W 4.4.0-gfxbench+ #1 [ 262.865060] Hardware name: DN2820FYK, BIOS FYBYT10H.86A.0038.2014.0717.1455 07/17/2014 [ 262.865064] ffffffffa0338cf8 ffff88007448ba78 ffffffff813df90c ffff88007448bac0 [ 262.865071] ffff88007448bab0 ffffffff810746e1 0000000000186500 0000000000000001 [ 262.865077] 0000000000000001 ffff880074420000 0000000000000000 ffff88007448bb10 [ 262.865083] Call Trace: [ 262.865092] [] dump_stack+0x4e/0x82 [ 262.865098] [] warn_slowpath_common+0x81/0xc0 [ 262.865102] [] warn_slowpath_fmt+0x47/0x50 [ 262.865128] [] __unclaimed_reg_debug+0x68/0x80 [i915] [ 262.865154] [] vlv_read32+0x2de/0x370 [i915] [ 262.865173] [] intel_set_memory_cxsr+0x87/0x1a0 [i915] [ 262.865200] [] intel_pre_plane_update+0xb3/0xf0 [i915] [ 262.865228] [] intel_atomic_commit+0x3b5/0x17c0 [i915] [ 262.865234] [] ? drm_atomic_check_only+0x145/0x660 [ 262.865239] [] ? drm_atomic_set_crtc_for_connector+0x6a/0xe0 [ 262.865243] [] drm_atomic_commit+0x32/0x50 [ 262.865249] [] drm_atomic_helper_set_config+0x75/0xb0 [ 262.865253] [] drm_mode_set_config_internal+0x60/0x110 [ 262.865258] [] drm_mode_setcrtc+0x186/0x4f0 [ 262.865263] [] drm_ioctl+0x13d/0x590 [ 262.865267] [] ? drm_mode_setplane+0x1b0/0x1b0 [ 262.865273] [] do_vfs_ioctl+0x2fc/0x550 [ 262.865278] [] ? vm_munmap+0x4a/0x60 [ 262.865283] [] ? __fget_light+0x6a/0x90 [ 262.865287] [] SyS_ioctl+0x3c/0x70 [ 262.865292] [] entry_SYSCALL_64_fastpath+0x16/0x73 [ 262.865296] ---[ end trace 6387a0ad001bb39f ]--- Testcase: kms_flip.basic-flip-vs-wf_vblank Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93698 Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1454514805-10595-4-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7fa627..5bc9a36 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4834,7 +4834,9 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state) if (pipe_config->disable_cxsr) { crtc->wm.cxsr_allowed = false; - intel_set_memory_cxsr(dev_priv, false); + + if (old_crtc_state->base.active) + intel_set_memory_cxsr(dev_priv, false); } if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed) -- cgit v0.10.2 From 7157bb27e79875db5603aa1e30f56e873a8300f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Fri, 5 Feb 2016 13:21:42 +0100 Subject: drm/i915/skl: Add missing SKL ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Used by production devices: Intel(R) Iris Graphics 540 (Skylake GT3e) Intel(R) Iris Graphics 550 (Skylake GT3e) v2: More ids v3: Less ids (GT1 got duplicated) Cc: Mika Kuoppala Signed-off-by: Michał Winiarski Reviewed-by: Mika Kuoppala Signed-off-by: Mika Kuoppala Link: http://patchwork.freedesktop.org/patch/msgid/1454674902-26207-1-git-send-email-michal.winiarski@intel.com diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 9b48ac1..9094599 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -277,7 +277,9 @@ INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */ #define INTEL_SKL_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ -- cgit v0.10.2 From 78385cb398748debb7ea2e36d6d2001830c172bc Mon Sep 17 00:00:00 2001 From: Lyude Date: Tue, 2 Feb 2016 10:49:43 -0500 Subject: drm/i915/skl: Don't skip mst encoders in skl_ddi_pll_select() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't actually check for INTEL_OUTPUT_DP_MST at all in here, as a result we skip assigning a DPLL to any DP MST ports, which makes link training fail: [ 1442.933896] [drm:intel_power_well_enable] enabling DDI D power well [ 1442.933905] [drm:skl_set_power_well] Enabling DDI D power well [ 1442.933957] [drm:intel_mst_pre_enable_dp] 0 [ 1442.935474] [drm:intel_dp_set_signal_levels] Using signal levels 00000000 [ 1442.935477] [drm:intel_dp_set_signal_levels] Using vswing level 0 [ 1442.935480] [drm:intel_dp_set_signal_levels] Using pre-emphasis level 0 [ 1442.936190] [drm:intel_dp_set_signal_levels] Using signal levels 05000000 [ 1442.936193] [drm:intel_dp_set_signal_levels] Using vswing level 1 [ 1442.936195] [drm:intel_dp_set_signal_levels] Using pre-emphasis level 1 [ 1442.936858] [drm:intel_dp_set_signal_levels] Using signal levels 08000000 [ 1442.936862] [drm:intel_dp_set_signal_levels] Using vswing level 2 … [ 1442.998253] [drm:intel_dp_link_training_clock_recovery [i915]] *ERROR* too many full retries, give up [ 1442.998512] [drm:intel_dp_start_link_train [i915]] *ERROR* failed to train DP, aborting After which the pipe state goes completely out of sync: [ 70.075596] [drm:check_crtc_state] [CRTC:25] [ 70.075696] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in ddi_pll_sel (expected 0x00000000, found 0x00000001) [ 70.075747] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in shared_dpll (expected -1, found 0) [ 70.075798] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in dpll_hw_state.ctrl1 (expected 0x00000000, found 0x00000021) [ 70.075840] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in dpll_hw_state.cfgcr1 (expected 0x00000000, found 0x80400173) [ 70.075884] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in dpll_hw_state.cfgcr2 (expected 0x00000000, found 0x000003a5) [ 70.075954] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in base.adjusted_mode.crtc_clock (expected 262750, found 72256) [ 70.075999] [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in port_clock (expected 540000, found 148500) And if you're especially lucky, it keeps going downhill: [ 83.309256] Kernel panic - not syncing: Timeout: Not all CPUs entered broadcast exception handler [ 83.309265] [ 83.309265] ================================= [ 83.309266] [ INFO: inconsistent lock state ] [ 83.309267] 4.5.0-rc1Lyude-Test #265 Not tainted [ 83.309267] --------------------------------- [ 83.309268] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. [ 83.309270] Xorg/1194 [HC0[1]:SC0[0]:HE1:SE1] takes: [ 83.309293] (&(&dev_priv->uncore.lock)->rlock){?.-...}, at: [] gen9_write32+0x63/0x400 [i915] [ 83.309293] {IN-HARDIRQ-W} state was registered at: [ 83.309297] [] __lock_acquire+0x9c4/0x1d00 [ 83.309299] [] lock_acquire+0xce/0x1c0 [ 83.309302] [] _raw_spin_lock_irqsave+0x56/0x90 [ 83.309321] [] gen9_read32+0x52/0x3d0 [i915] [ 83.309332] [] gen8_irq_handler+0x27a/0x6a0 [i915] [ 83.309337] [] handle_irq_event_percpu+0x41/0x300 [ 83.309339] [] handle_irq_event+0x39/0x60 [ 83.309341] [] handle_edge_irq+0x74/0x130 [ 83.309344] [] handle_irq+0x73/0x120 [ 83.309346] [] do_IRQ+0x61/0x120 [ 83.309348] [] ret_from_intr+0x0/0x20 [ 83.309351] [] cpuidle_enter_state+0x105/0x330 [ 83.309353] [] cpuidle_enter+0x17/0x20 [ 83.309356] [] call_cpuidle+0x2a/0x50 [ 83.309358] [] cpu_startup_entry+0x26d/0x3a0 [ 83.309360] [] rest_init+0x13a/0x140 [ 83.309363] [] start_kernel+0x475/0x482 [ 83.309365] [] x86_64_start_reservations+0x2a/0x2c [ 83.309367] [] x86_64_start_kernel+0x13b/0x14a Fixes: 82d354370189 ("drm/i915/skl: Implementation of SKL DPLL programming") Signed-off-by: Lyude Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454428183-994-1-git-send-email-cpaul@redhat.com diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6d5b09f..32c8991 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1531,7 +1531,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | wrpll_params.central_freq; - } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { + } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type == INTEL_OUTPUT_DP_MST) { switch (crtc_state->port_clock / 2) { case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); -- cgit v0.10.2 From 5a01d5b61399fb03ffd54edfb68dca411d89dcda Mon Sep 17 00:00:00 2001 From: Lyude Date: Tue, 2 Feb 2016 09:35:09 -0500 Subject: drm/i915/skl: Explicitly check for eDP in skl_ddi_pll_select() Assuming any connector that isn't DP, MST, or HDMI is eDP definitely seems likely to cover up other bugs in the future. Signed-off-by: Lyude Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454423709-21882-2-git-send-email-cpaul@redhat.com diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 32c8991..cdf2e14 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1546,8 +1546,10 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, } cfgcr1 = cfgcr2 = 0; - } else /* eDP */ + } else if (intel_encoder->type == INTEL_OUTPUT_EDP) { return true; + } else + return false; memset(&crtc_state->dpll_hw_state, 0, sizeof(crtc_state->dpll_hw_state)); -- cgit v0.10.2 From af3997b569dbd2ff50318c874fa4618d8b628fb0 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 5 Feb 2016 13:29:28 +0200 Subject: drm/i915: Skip DDI PLL selection for DSI Skip DDI PLL selection if display type is DSI/MIPI. Signed-off-by: Mika Kahola Reviewed-by: Sivakumar Thulasimani Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1454671768-27062-1-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5bc9a36..76421c9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9848,8 +9848,13 @@ static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state) static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { - if (!intel_ddi_pll_select(crtc, crtc_state)) - return -EINVAL; + struct intel_encoder *intel_encoder = + intel_ddi_get_crtc_new_encoder(crtc_state); + + if (intel_encoder->type != INTEL_OUTPUT_DSI) { + if (!intel_ddi_pll_select(crtc, crtc_state)) + return -EINVAL; + } crtc->lowfreq_avail = false; -- cgit v0.10.2 From da3b891b0fb88605bb2d16adaf1ef2a1f16403ba Mon Sep 17 00:00:00 2001 From: Lyude Date: Thu, 4 Feb 2016 10:43:21 -0500 Subject: drm/i915/skl: Fix typo in DPLL_CFGCR1 definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We accidentally point both cfgcr registers for the second shared DPLL to the same location in i915_reg.h. This results in a lot of hw pipe state mismatches whenever we try to do a modeset that requires allocating the DPLL to a CRTC: [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in dpll_hw_state.cfgcr1 (expected 0x80000168, found 0x000004a5) [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in base.adjusted_mode.crtc_clock (expected 108000, found 49500) [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in port_clock (expected 108000, found 49500) This usually ends up causing blank monitors, since the DPLL never can get set to the right clock. Fixes: 086f8e84a085 ("drm/i915: Prefix raw register defines with underscore") Signed-off-by: Lyude Cc: drm-intel-fixes@lists.freedesktop.org Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454600601-21900-1-git-send-email-cpaul@redhat.com diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 188ad5d..665ae48 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7545,7 +7545,7 @@ enum skl_disp_power_wells { #define DPLL_CFGCR2_PDIV_7 (4<<2) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) -#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2) +#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1) #define DPLL_CFGCR2(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2) /* BXT display engine PLL */ -- cgit v0.10.2 From 8c448cadd4dd1bb3a8f34a93eaceb464d6e7a1db Mon Sep 17 00:00:00 2001 From: Gabriel Feceoru Date: Fri, 22 Jan 2016 13:28:45 +0200 Subject: drm/i915: Handle PipeC fused off on IVB/HSW/BDW Some Gen7/8 production parts may have the Display Pipe C fused off. In this case, the display hardware will prevent the enable bit in PIPE_CONF register (for Pipe C) from being set to 1. Fixed by adjusting pipe_count to reflect this. v2: Rename HSW_PIPE_C_DISABLE to IVB_PIPE_C_DISABLE as it already exists on ivybridge (Ville) v3: Remove unnecessary MMIO read, correct the description (Damien) v4: Be more specific in description (Patrick) Signed-off-by: Gabriel Feceoru Reviewed-by: Patrik Jakobsson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453462125-21519-1-git-send-email-gabriel.feceoru@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a42eb58..35c2b33 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -808,6 +808,9 @@ static void intel_device_info_runtime_init(struct drm_device *dev) !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) { DRM_INFO("Display fused off, disabling\n"); info->num_pipes = 0; + } else if (fuse_strap & IVB_PIPE_C_DISABLE) { + DRM_INFO("PipeC fused off\n"); + info->num_pipes -= 1; } } else if (info->num_pipes > 0 && INTEL_INFO(dev)->gen == 9) { u32 dfsm = I915_READ(SKL_DFSM); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 665ae48..144586e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5949,6 +5949,7 @@ enum skl_disp_power_wells { #define ILK_INTERNAL_GRAPHICS_DISABLE (1 << 31) #define ILK_INTERNAL_DISPLAY_DISABLE (1 << 30) #define ILK_DISPLAY_DEBUG_DISABLE (1 << 29) +#define IVB_PIPE_C_DISABLE (1 << 28) #define ILK_HDCP_DISABLE (1 << 25) #define ILK_eDP_A_DISABLE (1 << 24) #define HSW_CDCLK_LIMIT (1 << 24) -- cgit v0.10.2 From 1b39a917a9e00378c02c50ad86632ed3d872bfad Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Fri, 22 Jan 2016 23:10:06 +0000 Subject: drm/i915: fix context/engine cleanup order Swap the order of context & engine cleanup, so that contexts are cleaned up first, and *then* engines. This is a more sensible order anyway, but in particular has become necessary since the 'intel_ring_initialized() must be simple and inline' patch, which now uses ring->dev as an 'initialised' flag, so it can now be NULL after engine teardown. This in turn can cause a problem in the context code, which (used to) check the ring->dev->struct_mutex -- causing a fault if ring->dev was NULL. Also rename the cleanup function to reflect what it actually does (cleanup engines, not a ringbuffer), and fix an annoying whitespace issue. v2: Also make the fix in i915_load_modeset_init, not just in i915_driver_unload (Chris Wilson) v3: Had extra stuff in it. v4: Reverted extra stuff (so we're back to v2). Rebased and updated commentary above (Dave Gordon). Signed-off-by: Nick Hoath Signed-off-by: David Gordon Reviewed-by: Chris Wilson Cc: Mika Kuoppala Cc: Daniel Vetter Cc: Chris Wilson Signed-off-by: Dave Gordon Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453504211-7982-2-git-send-email-david.s.gordon@intel.com diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 35c2b33..571d7e6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -444,8 +444,8 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: mutex_lock(&dev->struct_mutex); - i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); + i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); cleanup_irq: intel_guc_ucode_fini(dev); @@ -1256,8 +1256,8 @@ int i915_driver_unload(struct drm_device *dev) intel_guc_ucode_fini(dev); mutex_lock(&dev->struct_mutex); - i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); + i915_gem_cleanup_engines(dev); mutex_unlock(&dev->struct_mutex); intel_fbc_cleanup_cfb(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8216665..e11eef1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3058,7 +3058,7 @@ int i915_gem_init_rings(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice); void i915_gem_init_swizzling(struct drm_device *dev); -void i915_gem_cleanup_ringbuffer(struct drm_device *dev); +void i915_gem_cleanup_engines(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct drm_i915_gem_request *req, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e9b19bc..de57e7f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4913,7 +4913,7 @@ i915_gem_init_hw(struct drm_device *dev) req = i915_gem_request_alloc(ring, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -4926,7 +4926,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -4934,7 +4934,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); - i915_gem_cleanup_ringbuffer(dev); + i915_gem_cleanup_engines(dev); goto out; } @@ -5009,7 +5009,7 @@ out_unlock: } void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) +i915_gem_cleanup_engines(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; @@ -5018,13 +5018,14 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) for_each_ring(ring, dev_priv, i) dev_priv->gt.cleanup_ring(ring); - if (i915.enable_execlists) - /* - * Neither the BIOS, ourselves or any other kernel - * expects the system to be in execlists mode on startup, - * so we need to reset the GPU back to legacy mode. - */ - intel_gpu_reset(dev); + if (i915.enable_execlists) { + /* + * Neither the BIOS, ourselves or any other kernel + * expects the system to be in execlists mode on startup, + * so we need to reset the GPU back to legacy mode. + */ + intel_gpu_reset(dev); + } } static void -- cgit v0.10.2 From 06e6ff8f10513ae863adeddf21510c99171a6283 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 28 Jan 2016 17:18:41 +0000 Subject: drm/i915: Capture PCI revision and subsytem details in error state Revision id along with device id is useful in better identification of the HW and its limitations so include this detail in error state. v2: make it clear that it is PCI revision and We might as well dump PCI subsystem details while we update this (Ville, Chris). Cc: Chris Wilson Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454001521-7701-1-git-send-email-arun.siluvery@linux.intel.com diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 7eeb244..978c026 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -365,6 +365,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, err_printf(m, "Reset count: %u\n", error->reset_count); err_printf(m, "Suspend count: %u\n", error->suspend_count); err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device); + err_printf(m, "PCI Revision: 0x%02x\n", dev->pdev->revision); + err_printf(m, "PCI Subsystem: %04x:%04x\n", + dev->pdev->subsystem_vendor, + dev->pdev->subsystem_device); err_printf(m, "IOMMU enabled?: %d\n", error->iommu); if (HAS_CSR(dev)) { -- cgit v0.10.2 From 9f5ac8ed4013c616bd3b29147808c8b2f057c251 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Jan 2016 14:37:58 +0100 Subject: agp/intel-gtt: Don't leak the scratch page Recently discovered by enabling CONFIG_DMA_API_DEBUG in our CI. By the looks of it broken since forever. v2: Don't forget to set the scratch page back to wb (Chris). Reuse intel_gtt_teardown_scratch_page for that (and fix it up to treat needs_dmar y/n correctly). Cc: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93793 Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453901881-26425-1-git-send-email-daniel.vetter@ffwll.ch diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 1341a94..e657f98 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -555,8 +555,10 @@ static unsigned int intel_gtt_mappable_entries(void) static void intel_gtt_teardown_scratch_page(void) { set_pages_wb(intel_private.scratch_page, 1); - pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (intel_private.needs_dmar) + pci_unmap_page(intel_private.pcidev, + intel_private.scratch_page_dma, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); __free_page(intel_private.scratch_page); } @@ -1430,6 +1432,8 @@ void intel_gmch_remove(void) if (--intel_private.refcount) return; + if (intel_private.scratch_page) + intel_gtt_teardown_scratch_page(); if (intel_private.pcidev) pci_dev_put(intel_private.pcidev); if (intel_private.bridge_dev) -- cgit v0.10.2 From 3e99a6b9561402909fdb3b0028764d42557e0103 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Jan 2016 14:37:59 +0100 Subject: drm/i915: Stop depending upon CONFIG_AGP_INTEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AGP_INTEL driver provides an interface for very old userspace to control the GART (though the GART itself was only ever emulated on Intel systems). The pci bridge discovery code is also used by the i915.ko driver to set up the GTT on old systems, but it does not require the old userspace interface. When i915.ko selects the old interface, it binds another user to the core GTT routines, and in particular creates a second reference to the scratch pages allocated. This hinders resource leak debugging for when we unload i915.ko as we want to assert that all DMA pages have been released, but we appear to leak because of the secondary interface which persists after i915.ko unloads. All i915.ko users do not require the old /dev/agpgart interface so stop selecting it and simplify our debugging by dropping the historical baggage. Note that by selecting AGP=n it was already possible to unselect AGP_INTEL. But since we've dropped support for any of the AGP stuff long ago there's really no point for this any more. Also note that we still need INTEL_GTT, which is the underlying, shared, driver for the graphics GART on gen1-5. v2: Entirely new commit message (Chris, Ville). Cc: Ville Syrjälä Cc: Chris Wilson Signed-off-by: Daniel Vetter Reviewed-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453901881-26425-2-git-send-email-daniel.vetter@ffwll.ch diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 051eab3..4c59793 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -2,9 +2,7 @@ config DRM_I915 tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" depends on DRM depends on X86 && PCI - depends on (AGP || AGP=n) select INTEL_GTT - select AGP_INTEL if AGP select INTERVAL_TREE # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs -- cgit v0.10.2 From 2417c8c03f508841b85bf61acc91836b7b0e2560 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 9 Feb 2016 21:11:13 +0100 Subject: drm/i915: fix error path in intel_setup_gmbus() This fails to undo the setup for pin==0; moreover, something interesting happens if the setup failed already at pin==0. Signed-off-by: Rasmus Villemoes Fixes: f899fc64cda8 ("drm/i915: use GMBUS to manage i2c links") Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1455048677-19882-3-git-send-email-linux@rasmusvillemoes.dk diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 25254b5..deb8282 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -683,7 +683,7 @@ int intel_setup_gmbus(struct drm_device *dev) return 0; err: - while (--pin) { + while (pin--) { if (!intel_gmbus_is_valid_pin(dev_priv, pin)) continue; -- cgit v0.10.2 From ff3dc0875cfa37851b9902c014b9eaa2f697400c Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 27 Jan 2016 15:43:49 +0000 Subject: drm/i915: check that rpm ref is held when accessing ringbuf in stolen mem While running some tests on the scheduler patches with rpm enabled I came across a corruption in the ringbuffer, which was root-caused to the GPU being suspended while commands were being emitted to the ringbuffer. The access to memory was failing because the GPU needs to be awake when accessing stolen memory (where my ringbuffer was located). Since we have this constraint it looks like a sensible idea to check that we hold a refcount when we access the rungbuffer. v2: move the check from ring_begin to ringbuffer iomap time (Chris) v3: update comment (Chris) Cc: John Harrison Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453909429-11024-1-git-send-email-daniele.ceraolospurio@intel.com diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6f5b511..133321a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2119,6 +2119,9 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev, return ret; } + /* Access through the GTT requires the device to be awake. */ + assert_rpm_wakelock_held(dev_priv); + ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), ringbuf->size); if (ringbuf->virtual_start == NULL) { -- cgit v0.10.2 From 799487f51d7419e33736d81b0b9087b2aaa593af Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:38 +0200 Subject: drm/i915: DisplayPort pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to DisplayPort. V2: - removed computation for max DOT clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk renamed as max_dotclk Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-2-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a073f04..65d5084 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -203,6 +203,7 @@ intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; if (is_edp(intel_dp) && fixed_mode) { if (mode->hdisplay > fixed_mode->hdisplay) @@ -220,7 +221,7 @@ intel_dp_mode_valid(struct drm_connector *connector, max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); mode_rate = intel_dp_link_required(target_clock, 18); - if (mode_rate > max_rate) + if (mode_rate > max_rate || target_clock > max_dotclk) return MODE_CLOCK_HIGH; if (mode->clock < 10000) -- cgit v0.10.2 From 587bf496d6186332ff863abffcf314b374c569e1 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:39 +0200 Subject: drm/i915: HDMI pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to HDMI. V2: - removed computation for max dot clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk variable renamed as max_dotclk - check for stereo mode added Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-3-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8698a64..edb7e90 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1202,11 +1202,19 @@ intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_device *dev = intel_hdmi_to_dev(hdmi); enum drm_mode_status status; int clock; + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; clock = mode->clock; + + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + clock *= 2; + + if (clock > max_dotclk) + return MODE_CLOCK_HIGH; + if (mode->flags & DRM_MODE_FLAG_DBLCLK) clock *= 2; -- cgit v0.10.2 From 832d5bfd67f9b723b7b5662b8c187b43aa5d2ac8 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:40 +0200 Subject: drm/i915: DisplayPort-MST pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to DisplayPort MST. V2: - removed computation for max pixel clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk variable renamed as max_dotclk Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-4-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 2a2ab30..a2bd698 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -371,6 +371,8 @@ static enum drm_mode_status intel_dp_mst_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + /* TODO - validate mode against available PBN for link */ if (mode->clock < 10000) return MODE_CLOCK_LOW; @@ -378,6 +380,9 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; + if (mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; + return MODE_OK; } -- cgit v0.10.2 From 24b23882773c5a7bf7767dbbc97e8e70e3c63bd6 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:41 +0200 Subject: drm/i915: SDVO pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to SDVO. V2: - removed computation for max pixel clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk variable renamed as max_dotclk Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-5-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2e1da06..4ecc076 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1527,6 +1527,7 @@ intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -1537,6 +1538,9 @@ intel_sdvo_mode_valid(struct drm_connector *connector, if (intel_sdvo->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; + if (mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; + if (intel_sdvo->is_lvds) { if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; -- cgit v0.10.2 From f8700b34bd8f0433e6f7a5538c474a3dfcb4cc44 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:42 +0200 Subject: drm/i915: CRT pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to CRT. V2: - removed computation for max pixel clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk variable renamed as max_dotclk Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-6-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 9c89df1..ad5dfab 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -216,6 +216,7 @@ intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; + int max_dotclk = to_i915(dev)->max_dotclk_freq; int max_clock = 0; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -231,6 +232,9 @@ intel_crt_mode_valid(struct drm_connector *connector, if (mode->clock > max_clock) return MODE_CLOCK_HIGH; + if (mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; + /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */ if (HAS_PCH_LPT(dev) && (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2)) -- cgit v0.10.2 From 54c032b354fa74bab32fc7b8c020d4e1934dc654 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Tue, 2 Feb 2016 15:16:43 +0200 Subject: drm/i915: TV pixel clock check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible the we request to have a mode that has higher pixel clock than our HW can support. This patch checks if requested pixel clock is lower than the one supported by the HW. The requested mode is discarded if we cannot support the requested pixel clock. This patch applies to TV. V2: - removed computation for max pixel clock V3: - cleanup by removing unnecessary lines V4: - max_pixclk variable renamed as max_dotclk Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1454419003-6001-7-git-send-email-mika.kahola@intel.com diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 5034b00..d21f75b 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -897,6 +897,10 @@ intel_tv_mode_valid(struct drm_connector *connector, { struct intel_tv *intel_tv = intel_attached_tv(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + + if (mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; /* Ensure TV refresh is close to desired refresh */ if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) -- cgit v0.10.2 From ebb7c78d358b2ea45c7d997423e6feb42e5ce4ef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Jan 2016 14:38:00 +0100 Subject: agp/intel-gtt: Only register fake agp driver for gen1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fake agp driver for the intel graphics gart is only needed for ums support. And we ditched that a long time ago: commit 03dae59c72ffffd8ef6e005f48ba356c863e0587 Author: Daniel Vetter Date: Wed Jul 23 16:27:25 2014 +0200 drm/i915: Ditch UMS config option With this there's no longer the problem that 2 drivers (fake agp driver and the drm/i915 driver) fight over the same piece, which fixes apparent dma leaks detected by CONFIG_DMA_API_DEBUG. Note that the leak isn't real since intel-gtt refcounts and will tear down eventually. But the debug code assumes that when the i915 driver unbinds from the pci device everything should be gone. Which isn't the case if we have intel-agp enabled - userspace might need it. But by ditching this intel-gtt setup and teardown is completely tied to the livetime of the "real" driver. While at it untangle the init ordering a bit - the fake agp wouldn't be initialized correctly if i915.ko loads first. Which isn't a problem since when i915 loads in kms mode you won't need the fake agp support needed by the ums driver ... Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93793 Signed-off-by: Daniel Vetter Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453901881-26425-3-git-send-email-daniel.vetter@ffwll.ch diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e657f98..aef87fd 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1348,16 +1348,6 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, { int i, mask; - /* - * Can be called from the fake agp driver but also directly from - * drm/i915.ko. Hence we need to check whether everything is set up - * already. - */ - if (intel_private.driver) { - intel_private.refcount++; - return 1; - } - for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { if (gpu_pdev) { if (gpu_pdev->device == @@ -1378,16 +1368,26 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, if (!intel_private.driver) return 0; - intel_private.refcount++; - #if IS_ENABLED(CONFIG_AGP_INTEL) if (bridge) { + if (INTEL_GTT_GEN > 1) + return 0; + bridge->driver = &intel_fake_agp_driver; bridge->dev_private_data = &intel_private; bridge->dev = bridge_pdev; } #endif + + /* + * Can be called from the fake agp driver but also directly from + * drm/i915.ko. Hence we need to check whether everything is set up + * already. + */ + if (intel_private.refcount++) + return 1; + intel_private.bridge_dev = pci_dev_get(bridge_pdev); dev_info(&bridge_pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); -- cgit v0.10.2 From d28d4731ac9f688166daf7ae44d1d4eb060ea64a Mon Sep 17 00:00:00 2001 From: Abhay Kumar Date: Fri, 22 Jan 2016 17:39:04 -0800 Subject: drm/i915: edp resume/On time optimization. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make resume/on codepath not to wait for panel_power_cycle_delay(t11_t12) if this time is already spent in suspend/poweron time. v2: Use CLOCK_BOOTTIME and remove jiffies for panel power cycle delay calculation(Ville). v3: Addressed below comments 1. Tracking time from where last powercycle is initiated. 2. Used ktime_get_bootime() wrapper for boottime clock. 3. Used ktime_ms_delta() to get time difference. v4: Updated v3 change log in detail. v5: Removed static from panel_power_on_time(Stéphane). Cc: Ville Syrjälä Signed-off-by: Abhay Kumar Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1453513144-14135-1-git-send-email-abhay.kumar@intel.com diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 65d5084..388ee02 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1815,12 +1815,21 @@ static void wait_panel_off(struct intel_dp *intel_dp) static void wait_panel_power_cycle(struct intel_dp *intel_dp) { + ktime_t panel_power_on_time; + s64 panel_power_off_duration; + DRM_DEBUG_KMS("Wait for panel power cycle\n"); + /* take the difference of currrent time and panel power off time + * and then make panel wait for t11_t12 if needed. */ + panel_power_on_time = ktime_get_boottime(); + panel_power_off_duration = ktime_ms_delta(panel_power_on_time, intel_dp->panel_power_off_time); + /* When we disable the VDD override bit last we have to do the manual * wait. */ - wait_remaining_ms_from_jiffies(intel_dp->last_power_cycle, - intel_dp->panel_power_cycle_delay); + if (panel_power_off_duration < (s64)intel_dp->panel_power_cycle_delay) + wait_remaining_ms_from_jiffies(jiffies, + intel_dp->panel_power_cycle_delay - panel_power_off_duration); wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE); } @@ -1972,7 +1981,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); if ((pp & POWER_TARGET_ON) == 0) - intel_dp->last_power_cycle = jiffies; + intel_dp->panel_power_off_time = ktime_get_boottime(); power_domain = intel_display_port_aux_power_domain(intel_encoder); intel_display_power_put(dev_priv, power_domain); @@ -2121,7 +2130,7 @@ static void edp_panel_off(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - intel_dp->last_power_cycle = jiffies; + intel_dp->panel_power_off_time = ktime_get_boottime(); wait_panel_off(intel_dp); /* We got a reference when we enabled the VDD. */ @@ -5120,7 +5129,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp) { - intel_dp->last_power_cycle = jiffies; + intel_dp->panel_power_off_time = ktime_get_boottime(); intel_dp->last_power_on = jiffies; intel_dp->last_backlight_off = jiffies; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 878172a..3cae376 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -771,9 +771,9 @@ struct intel_dp { int backlight_off_delay; struct delayed_work panel_vdd_work; bool want_panel_vdd; - unsigned long last_power_cycle; unsigned long last_power_on; unsigned long last_backlight_off; + ktime_t panel_power_off_time; struct notifier_block edp_notifier; -- cgit v0.10.2 From 59bbf84d8958a6e6cf579c8ddcca88e3f3924dbd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 14 Feb 2016 22:40:52 +0100 Subject: drm/i915: Update DRIVER_DATE to 20160214 Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e11eef1..64cfd44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -59,7 +59,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20160124" +#define DRIVER_DATE "20160214" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v0.10.2