UAPI Changes:

- Expose RPCS (SSEU) configuration to userspace for Ice Lake
 in order to allow userspace to reconfigure the subslice config
 per context basis. (Tvrtko, Lionel)
 
 Driver Changes:
 
 - Execbuf and preemption improvements including selftests (Chris)
 - Rename HAS_GMCH_DISPLAY/HAS_GMCH (Rodrigo)
 - Debugfs error handling fix for robustness (Greg)
 - Improve reg_rw traces (Ville)
 - Push clear_intel_crtc_state onto the heap (Chris)
 - Watermark fixes for Ice Lake (Ville)
 - Fix enable count array size and bounds checking (Tvrtko)
 - MST Fixes (Lyude)
 - Prevent race and handle error on I915_GEM_MMAP (Joonas)
 - Initial rework for an full atomic gamma mode (Ville)
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJcXJw7AAoJEPpiX2QO6xPKWuQH/i3o86TqLheae2vdi8X/yp92
 XeZbmNfaL7Gui6ggZpRMREjIIiDZ0nFga5INcVtrak6JRjeefb+wQsy38tdb98ne
 EPn6eif0nO/uxc7BsdW2ndIDBSWC+ZW7gt4rzY5zLG/WCmX1qfOOS9GdUpXPF3jY
 sB8Af6lsGSxrCFkBzUB9Z7AyoP/Yq+YeamFOtXLufhtQb4GL3djjdugaUBBfQmNn
 FvZTxhhsXn3HU9Jy1AjRFALhqXvTjZt1L5myav4sCJ2qlsr2dL9y3c7evbO5jrZY
 4TSlKUi5XwfW1RlHTQN43fTq7yWFwoF1FsR4LaKS0a8bKIXiBLwset7YA1m6wmY=
 =Woo8
 -----END PGP SIGNATURE-----

Merge tag 'drm-intel-next-2019-02-07' of git://anongit.freedesktop.org/drm/drm-intel into drm-next

UAPI Changes:

- Expose RPCS (SSEU) configuration to userspace for Ice Lake
in order to allow userspace to reconfigure the subslice config
per context basis. (Tvrtko, Lionel)

Driver Changes:

- Execbuf and preemption improvements including selftests (Chris)
- Rename HAS_GMCH_DISPLAY/HAS_GMCH (Rodrigo)
- Debugfs error handling fix for robustness (Greg)
- Improve reg_rw traces (Ville)
- Push clear_intel_crtc_state onto the heap (Chris)
- Watermark fixes for Ice Lake (Ville)
- Fix enable count array size and bounds checking (Tvrtko)
- MST Fixes (Lyude)
- Prevent race and handle error on I915_GEM_MMAP (Joonas)
- Initial rework for an full atomic gamma mode (Ville)

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

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190208165000.GA30314@intel.com
This commit is contained in:
Dave Airlie 2019-02-11 13:41:53 +10:00
commit 5ea3998d56
55 changed files with 2761 additions and 942 deletions

View File

@ -57,7 +57,9 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o intel_pipe_crc.o
i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o
# GEM code
i915-y += i915_cmd_parser.o \
i915-y += \
i915_active.o \
i915_cmd_parser.o \
i915_gem_batch_pool.o \
i915_gem_clflush.o \
i915_gem_context.o \

View File

@ -0,0 +1,286 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2019 Intel Corporation
*/
#include "i915_drv.h"
#include "i915_active.h"
#define BKL(ref) (&(ref)->i915->drm.struct_mutex)
/*
* Active refs memory management
*
* To be more economical with memory, we reap all the i915_active trees as
* they idle (when we know the active requests are inactive) and allocate the
* nodes from a local slab cache to hopefully reduce the fragmentation.
*/
static struct i915_global_active {
struct kmem_cache *slab_cache;
} global;
struct active_node {
struct i915_active_request base;
struct i915_active *ref;
struct rb_node node;
u64 timeline;
};
static void
__active_park(struct i915_active *ref)
{
struct active_node *it, *n;
rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
GEM_BUG_ON(i915_active_request_isset(&it->base));
kmem_cache_free(global.slab_cache, it);
}
ref->tree = RB_ROOT;
}
static void
__active_retire(struct i915_active *ref)
{
GEM_BUG_ON(!ref->count);
if (--ref->count)
return;
/* return the unused nodes to our slabcache */
__active_park(ref);
ref->retire(ref);
}
static void
node_retire(struct i915_active_request *base, struct i915_request *rq)
{
__active_retire(container_of(base, struct active_node, base)->ref);
}
static void
last_retire(struct i915_active_request *base, struct i915_request *rq)
{
__active_retire(container_of(base, struct i915_active, last));
}
static struct i915_active_request *
active_instance(struct i915_active *ref, u64 idx)
{
struct active_node *node;
struct rb_node **p, *parent;
struct i915_request *old;
/*
* We track the most recently used timeline to skip a rbtree search
* for the common case, under typical loads we never need the rbtree
* at all. We can reuse the last slot if it is empty, that is
* after the previous activity has been retired, or if it matches the
* current timeline.
*
* Note that we allow the timeline to be active simultaneously in
* the rbtree and the last cache. We do this to avoid having
* to search and replace the rbtree element for a new timeline, with
* the cost being that we must be aware that the ref may be retired
* twice for the same timeline (as the older rbtree element will be
* retired before the new request added to last).
*/
old = i915_active_request_raw(&ref->last, BKL(ref));
if (!old || old->fence.context == idx)
goto out;
/* Move the currently active fence into the rbtree */
idx = old->fence.context;
parent = NULL;
p = &ref->tree.rb_node;
while (*p) {
parent = *p;
node = rb_entry(parent, struct active_node, node);
if (node->timeline == idx)
goto replace;
if (node->timeline < idx)
p = &parent->rb_right;
else
p = &parent->rb_left;
}
node = kmem_cache_alloc(global.slab_cache, GFP_KERNEL);
/* kmalloc may retire the ref->last (thanks shrinker)! */
if (unlikely(!i915_active_request_raw(&ref->last, BKL(ref)))) {
kmem_cache_free(global.slab_cache, node);
goto out;
}
if (unlikely(!node))
return ERR_PTR(-ENOMEM);
i915_active_request_init(&node->base, NULL, node_retire);
node->ref = ref;
node->timeline = idx;
rb_link_node(&node->node, parent, p);
rb_insert_color(&node->node, &ref->tree);
replace:
/*
* Overwrite the previous active slot in the rbtree with last,
* leaving last zeroed. If the previous slot is still active,
* we must be careful as we now only expect to receive one retire
* callback not two, and so much undo the active counting for the
* overwritten slot.
*/
if (i915_active_request_isset(&node->base)) {
/* Retire ourselves from the old rq->active_list */
__list_del_entry(&node->base.link);
ref->count--;
GEM_BUG_ON(!ref->count);
}
GEM_BUG_ON(list_empty(&ref->last.link));
list_replace_init(&ref->last.link, &node->base.link);
node->base.request = fetch_and_zero(&ref->last.request);
out:
return &ref->last;
}
void i915_active_init(struct drm_i915_private *i915,
struct i915_active *ref,
void (*retire)(struct i915_active *ref))
{
ref->i915 = i915;
ref->retire = retire;
ref->tree = RB_ROOT;
i915_active_request_init(&ref->last, NULL, last_retire);
ref->count = 0;
}
int i915_active_ref(struct i915_active *ref,
u64 timeline,
struct i915_request *rq)
{
struct i915_active_request *active;
active = active_instance(ref, timeline);
if (IS_ERR(active))
return PTR_ERR(active);
if (!i915_active_request_isset(active))
ref->count++;
__i915_active_request_set(active, rq);
GEM_BUG_ON(!ref->count);
return 0;
}
bool i915_active_acquire(struct i915_active *ref)
{
lockdep_assert_held(BKL(ref));
return !ref->count++;
}
void i915_active_release(struct i915_active *ref)
{
lockdep_assert_held(BKL(ref));
__active_retire(ref);
}
int i915_active_wait(struct i915_active *ref)
{
struct active_node *it, *n;
int ret = 0;
if (i915_active_acquire(ref))
goto out_release;
ret = i915_active_request_retire(&ref->last, BKL(ref));
if (ret)
goto out_release;
rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
ret = i915_active_request_retire(&it->base, BKL(ref));
if (ret)
break;
}
out_release:
i915_active_release(ref);
return ret;
}
int i915_request_await_active_request(struct i915_request *rq,
struct i915_active_request *active)
{
struct i915_request *barrier =
i915_active_request_raw(active, &rq->i915->drm.struct_mutex);
return barrier ? i915_request_await_dma_fence(rq, &barrier->fence) : 0;
}
int i915_request_await_active(struct i915_request *rq, struct i915_active *ref)
{
struct active_node *it, *n;
int ret;
ret = i915_request_await_active_request(rq, &ref->last);
if (ret)
return ret;
rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
ret = i915_request_await_active_request(rq, &it->base);
if (ret)
return ret;
}
return 0;
}
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
void i915_active_fini(struct i915_active *ref)
{
GEM_BUG_ON(i915_active_request_isset(&ref->last));
GEM_BUG_ON(!RB_EMPTY_ROOT(&ref->tree));
GEM_BUG_ON(ref->count);
}
#endif
int i915_active_request_set(struct i915_active_request *active,
struct i915_request *rq)
{
int err;
/* Must maintain ordering wrt previous active requests */
err = i915_request_await_active_request(rq, active);
if (err)
return err;
__i915_active_request_set(active, rq);
return 0;
}
void i915_active_retire_noop(struct i915_active_request *active,
struct i915_request *request)
{
/* Space left intentionally blank */
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/i915_active.c"
#endif
int __init i915_global_active_init(void)
{
global.slab_cache = KMEM_CACHE(active_node, SLAB_HWCACHE_ALIGN);
if (!global.slab_cache)
return -ENOMEM;
return 0;
}
void __exit i915_global_active_exit(void)
{
kmem_cache_destroy(global.slab_cache);
}

View File

@ -0,0 +1,425 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2019 Intel Corporation
*/
#ifndef _I915_ACTIVE_H_
#define _I915_ACTIVE_H_
#include <linux/lockdep.h>
#include "i915_active_types.h"
#include "i915_request.h"
/*
* We treat requests as fences. This is not be to confused with our
* "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
* We use the fences to synchronize access from the CPU with activity on the
* GPU, for example, we should not rewrite an object's PTE whilst the GPU
* is reading them. We also track fences at a higher level to provide
* implicit synchronisation around GEM objects, e.g. set-domain will wait
* for outstanding GPU rendering before marking the object ready for CPU
* access, or a pageflip will wait until the GPU is complete before showing
* the frame on the scanout.
*
* In order to use a fence, the object must track the fence it needs to
* serialise with. For example, GEM objects want to track both read and
* write access so that we can perform concurrent read operations between
* the CPU and GPU engines, as well as waiting for all rendering to
* complete, or waiting for the last GPU user of a "fence register". The
* object then embeds a #i915_active_request to track the most recent (in
* retirement order) request relevant for the desired mode of access.
* The #i915_active_request is updated with i915_active_request_set() to
* track the most recent fence request, typically this is done as part of
* i915_vma_move_to_active().
*
* When the #i915_active_request completes (is retired), it will
* signal its completion to the owner through a callback as well as mark
* itself as idle (i915_active_request.request == NULL). The owner
* can then perform any action, such as delayed freeing of an active
* resource including itself.
*/
void i915_active_retire_noop(struct i915_active_request *active,
struct i915_request *request);
/**
* i915_active_request_init - prepares the activity tracker for use
* @active - the active tracker
* @rq - initial request to track, can be NULL
* @func - a callback when then the tracker is retired (becomes idle),
* can be NULL
*
* i915_active_request_init() prepares the embedded @active struct for use as
* an activity tracker, that is for tracking the last known active request
* associated with it. When the last request becomes idle, when it is retired
* after completion, the optional callback @func is invoked.
*/
static inline void
i915_active_request_init(struct i915_active_request *active,
struct i915_request *rq,
i915_active_retire_fn retire)
{
RCU_INIT_POINTER(active->request, rq);
INIT_LIST_HEAD(&active->link);
active->retire = retire ?: i915_active_retire_noop;
}
#define INIT_ACTIVE_REQUEST(name) i915_active_request_init((name), NULL, NULL)
/**
* i915_active_request_set - updates the tracker to watch the current request
* @active - the active tracker
* @request - the request to watch
*
* __i915_active_request_set() watches the given @request for completion. Whilst
* that @request is busy, the @active reports busy. When that @request is
* retired, the @active tracker is updated to report idle.
*/
static inline void
__i915_active_request_set(struct i915_active_request *active,
struct i915_request *request)
{
list_move(&active->link, &request->active_list);
rcu_assign_pointer(active->request, request);
}
int __must_check
i915_active_request_set(struct i915_active_request *active,
struct i915_request *rq);
/**
* i915_active_request_set_retire_fn - updates the retirement callback
* @active - the active tracker
* @fn - the routine called when the request is retired
* @mutex - struct_mutex used to guard retirements
*
* i915_active_request_set_retire_fn() updates the function pointer that
* is called when the final request associated with the @active tracker
* is retired.
*/
static inline void
i915_active_request_set_retire_fn(struct i915_active_request *active,
i915_active_retire_fn fn,
struct mutex *mutex)
{
lockdep_assert_held(mutex);
active->retire = fn ?: i915_active_retire_noop;
}
static inline struct i915_request *
__i915_active_request_peek(const struct i915_active_request *active)
{
/*
* Inside the error capture (running with the driver in an unknown
* state), we want to bend the rules slightly (a lot).
*
* Work is in progress to make it safer, in the meantime this keeps
* the known issue from spamming the logs.
*/
return rcu_dereference_protected(active->request, 1);
}
/**
* i915_active_request_raw - return the active request
* @active - the active tracker
*
* i915_active_request_raw() returns the current request being tracked, or NULL.
* It does not obtain a reference on the request for the caller, so the caller
* must hold struct_mutex.
*/
static inline struct i915_request *
i915_active_request_raw(const struct i915_active_request *active,
struct mutex *mutex)
{
return rcu_dereference_protected(active->request,
lockdep_is_held(mutex));
}
/**
* i915_active_request_peek - report the active request being monitored
* @active - the active tracker
*
* i915_active_request_peek() returns the current request being tracked if
* still active, or NULL. It does not obtain a reference on the request
* for the caller, so the caller must hold struct_mutex.
*/
static inline struct i915_request *
i915_active_request_peek(const struct i915_active_request *active,
struct mutex *mutex)
{
struct i915_request *request;
request = i915_active_request_raw(active, mutex);
if (!request || i915_request_completed(request))
return NULL;
return request;
}
/**
* i915_active_request_get - return a reference to the active request
* @active - the active tracker
*
* i915_active_request_get() returns a reference to the active request, or NULL
* if the active tracker is idle. The caller must hold struct_mutex.
*/
static inline struct i915_request *
i915_active_request_get(const struct i915_active_request *active,
struct mutex *mutex)
{
return i915_request_get(i915_active_request_peek(active, mutex));
}
/**
* __i915_active_request_get_rcu - return a reference to the active request
* @active - the active tracker
*
* __i915_active_request_get() returns a reference to the active request,
* or NULL if the active tracker is idle. The caller must hold the RCU read
* lock, but the returned pointer is safe to use outside of RCU.
*/
static inline struct i915_request *
__i915_active_request_get_rcu(const struct i915_active_request *active)
{
/*
* Performing a lockless retrieval of the active request is super
* tricky. SLAB_TYPESAFE_BY_RCU merely guarantees that the backing
* slab of request objects will not be freed whilst we hold the
* RCU read lock. It does not guarantee that the request itself
* will not be freed and then *reused*. Viz,
*
* Thread A Thread B
*
* rq = active.request
* retire(rq) -> free(rq);
* (rq is now first on the slab freelist)
* active.request = NULL
*
* rq = new submission on a new object
* ref(rq)
*
* To prevent the request from being reused whilst the caller
* uses it, we take a reference like normal. Whilst acquiring
* the reference we check that it is not in a destroyed state
* (refcnt == 0). That prevents the request being reallocated
* whilst the caller holds on to it. To check that the request
* was not reallocated as we acquired the reference we have to
* check that our request remains the active request across
* the lookup, in the same manner as a seqlock. The visibility
* of the pointer versus the reference counting is controlled
* by using RCU barriers (rcu_dereference and rcu_assign_pointer).
*
* In the middle of all that, we inspect whether the request is
* complete. Retiring is lazy so the request may be completed long
* before the active tracker is updated. Querying whether the
* request is complete is far cheaper (as it involves no locked
* instructions setting cachelines to exclusive) than acquiring
* the reference, so we do it first. The RCU read lock ensures the
* pointer dereference is valid, but does not ensure that the
* seqno nor HWS is the right one! However, if the request was
* reallocated, that means the active tracker's request was complete.
* If the new request is also complete, then both are and we can
* just report the active tracker is idle. If the new request is
* incomplete, then we acquire a reference on it and check that
* it remained the active request.
*
* It is then imperative that we do not zero the request on
* reallocation, so that we can chase the dangling pointers!
* See i915_request_alloc().
*/
do {
struct i915_request *request;
request = rcu_dereference(active->request);
if (!request || i915_request_completed(request))
return NULL;
/*
* An especially silly compiler could decide to recompute the
* result of i915_request_completed, more specifically
* re-emit the load for request->fence.seqno. A race would catch
* a later seqno value, which could flip the result from true to
* false. Which means part of the instructions below might not
* be executed, while later on instructions are executed. Due to
* barriers within the refcounting the inconsistency can't reach
* past the call to i915_request_get_rcu, but not executing
* that while still executing i915_request_put() creates
* havoc enough. Prevent this with a compiler barrier.
*/
barrier();
request = i915_request_get_rcu(request);
/*
* What stops the following rcu_access_pointer() from occurring
* before the above i915_request_get_rcu()? If we were
* to read the value before pausing to get the reference to
* the request, we may not notice a change in the active
* tracker.
*
* The rcu_access_pointer() is a mere compiler barrier, which
* means both the CPU and compiler are free to perform the
* memory read without constraint. The compiler only has to
* ensure that any operations after the rcu_access_pointer()
* occur afterwards in program order. This means the read may
* be performed earlier by an out-of-order CPU, or adventurous
* compiler.
*
* The atomic operation at the heart of
* i915_request_get_rcu(), see dma_fence_get_rcu(), is
* atomic_inc_not_zero() which is only a full memory barrier
* when successful. That is, if i915_request_get_rcu()
* returns the request (and so with the reference counted
* incremented) then the following read for rcu_access_pointer()
* must occur after the atomic operation and so confirm
* that this request is the one currently being tracked.
*
* The corresponding write barrier is part of
* rcu_assign_pointer().
*/
if (!request || request == rcu_access_pointer(active->request))
return rcu_pointer_handoff(request);
i915_request_put(request);
} while (1);
}
/**
* i915_active_request_get_unlocked - return a reference to the active request
* @active - the active tracker
*
* i915_active_request_get_unlocked() returns a reference to the active request,
* or NULL if the active tracker is idle. The reference is obtained under RCU,
* so no locking is required by the caller.
*
* The reference should be freed with i915_request_put().
*/
static inline struct i915_request *
i915_active_request_get_unlocked(const struct i915_active_request *active)
{
struct i915_request *request;
rcu_read_lock();
request = __i915_active_request_get_rcu(active);
rcu_read_unlock();
return request;
}
/**
* i915_active_request_isset - report whether the active tracker is assigned
* @active - the active tracker
*
* i915_active_request_isset() returns true if the active tracker is currently
* assigned to a request. Due to the lazy retiring, that request may be idle
* and this may report stale information.
*/
static inline bool
i915_active_request_isset(const struct i915_active_request *active)
{
return rcu_access_pointer(active->request);
}
/**
* i915_active_request_retire - waits until the request is retired
* @active - the active request on which to wait
*
* i915_active_request_retire() waits until the request is completed,
* and then ensures that at least the retirement handler for this
* @active tracker is called before returning. If the @active
* tracker is idle, the function returns immediately.
*/
static inline int __must_check
i915_active_request_retire(struct i915_active_request *active,
struct mutex *mutex)
{
struct i915_request *request;
long ret;
request = i915_active_request_raw(active, mutex);
if (!request)
return 0;
ret = i915_request_wait(request,
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
MAX_SCHEDULE_TIMEOUT);
if (ret < 0)
return ret;
list_del_init(&active->link);
RCU_INIT_POINTER(active->request, NULL);
active->retire(active, request);
return 0;
}
/*
* GPU activity tracking
*
* Each set of commands submitted to the GPU compromises a single request that
* signals a fence upon completion. struct i915_request combines the
* command submission, scheduling and fence signaling roles. If we want to see
* if a particular task is complete, we need to grab the fence (struct
* i915_request) for that task and check or wait for it to be signaled. More
* often though we want to track the status of a bunch of tasks, for example
* to wait for the GPU to finish accessing some memory across a variety of
* different command pipelines from different clients. We could choose to
* track every single request associated with the task, but knowing that
* each request belongs to an ordered timeline (later requests within a
* timeline must wait for earlier requests), we need only track the
* latest request in each timeline to determine the overall status of the
* task.
*
* struct i915_active provides this tracking across timelines. It builds a
* composite shared-fence, and is updated as new work is submitted to the task,
* forming a snapshot of the current status. It should be embedded into the
* different resources that need to track their associated GPU activity to
* provide a callback when that GPU activity has ceased, or otherwise to
* provide a serialisation point either for request submission or for CPU
* synchronisation.
*/
void i915_active_init(struct drm_i915_private *i915,
struct i915_active *ref,
void (*retire)(struct i915_active *ref));
int i915_active_ref(struct i915_active *ref,
u64 timeline,
struct i915_request *rq);
int i915_active_wait(struct i915_active *ref);
int i915_request_await_active(struct i915_request *rq,
struct i915_active *ref);
int i915_request_await_active_request(struct i915_request *rq,
struct i915_active_request *active);
bool i915_active_acquire(struct i915_active *ref);
static inline void i915_active_cancel(struct i915_active *ref)
{
GEM_BUG_ON(ref->count != 1);
ref->count = 0;
}
void i915_active_release(struct i915_active *ref);
static inline bool
i915_active_is_idle(const struct i915_active *ref)
{
return !ref->count;
}
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
void i915_active_fini(struct i915_active *ref);
#else
static inline void i915_active_fini(struct i915_active *ref) { }
#endif
int i915_global_active_init(void);
void i915_global_active_exit(void);
#endif /* _I915_ACTIVE_H_ */

View File

@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2019 Intel Corporation
*/
#ifndef _I915_ACTIVE_TYPES_H_
#define _I915_ACTIVE_TYPES_H_
#include <linux/rbtree.h>
#include <linux/rcupdate.h>
struct drm_i915_private;
struct i915_active_request;
struct i915_request;
typedef void (*i915_active_retire_fn)(struct i915_active_request *,
struct i915_request *);
struct i915_active_request {
struct i915_request __rcu *request;
struct list_head link;
i915_active_retire_fn retire;
};
struct i915_active {
struct drm_i915_private *i915;
struct rb_root tree;
struct i915_active_request last;
unsigned int count;
void (*retire)(struct i915_active *ref);
};
#endif /* _I915_ACTIVE_TYPES_H_ */

View File

@ -207,7 +207,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
if (vma->fence)
seq_printf(m, " , fence: %d%s",
vma->fence->id,
i915_gem_active_isset(&vma->last_fence) ? "*" : "");
i915_active_request_isset(&vma->last_fence) ? "*" : "");
seq_puts(m, ")");
}
if (obj->stolen)
@ -3728,7 +3728,7 @@ static int spr_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_i915_private *dev_priv = inode->i_private;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
return -ENODEV;
return single_open(file, spr_wm_latency_show, dev_priv);
@ -3738,7 +3738,7 @@ static int cur_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_i915_private *dev_priv = inode->i_private;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
return -ENODEV;
return single_open(file, cur_wm_latency_show, dev_priv);

View File

@ -2543,6 +2543,10 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *dev_priv)
static int vlv_wait_for_pw_status(struct drm_i915_private *dev_priv,
u32 mask, u32 val)
{
i915_reg_t reg = VLV_GTLC_PW_STATUS;
u32 reg_value;
int ret;
/* The HW does not like us polling for PW_STATUS frequently, so
* use the sleeping loop rather than risk the busy spin within
* intel_wait_for_register().
@ -2550,8 +2554,12 @@ static int vlv_wait_for_pw_status(struct drm_i915_private *dev_priv,
* Transitioning between RC6 states should be at most 2ms (see
* valleyview_enable_rps) so use a 3ms timeout.
*/
return wait_for((I915_READ_NOTRACE(VLV_GTLC_PW_STATUS) & mask) == val,
3);
ret = wait_for(((reg_value = I915_READ_NOTRACE(reg)) & mask) == val, 3);
/* just trace the final value */
trace_i915_reg_rw(false, reg, reg_value, sizeof(reg_value), true);
return ret;
}
int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on)

View File

@ -91,8 +91,8 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20190202"
#define DRIVER_TIMESTAMP 1549095268
#define DRIVER_DATE "20190207"
#define DRIVER_TIMESTAMP 1549572331
/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
* WARN_ON()) for hw state sanity checks to check for unexpected conditions
@ -323,8 +323,20 @@ struct drm_i915_display_funcs {
/* display clock increase/decrease */
/* pll clock increase/decrease */
void (*load_csc_matrix)(struct intel_crtc_state *crtc_state);
void (*load_luts)(struct intel_crtc_state *crtc_state);
/*
* Program double buffered color management registers during
* vblank evasion. The registers should then latch during the
* next vblank start, alongside any other double buffered registers
* involved with the same commit.
*/
void (*color_commit)(const struct intel_crtc_state *crtc_state);
/*
* Load LUTs (and other single buffered color management
* registers). Will (hopefully) be called during the vblank
* following the latching of any double buffered registers
* involved with the same commit.
*/
void (*load_luts)(const struct intel_crtc_state *crtc_state);
};
#define CSR_VERSION(major, minor) ((major) << 16 | (minor))
@ -2490,7 +2502,7 @@ static inline unsigned int i915_sg_segment_size(void)
#define HAS_FW_BLC(dev_priv) (INTEL_GEN(dev_priv) > 2)
#define HAS_FBC(dev_priv) (INTEL_INFO(dev_priv)->display.has_fbc)
#define HAS_CUR_FBC(dev_priv) (!HAS_GMCH_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 7)
#define HAS_CUR_FBC(dev_priv) (!HAS_GMCH(dev_priv) && INTEL_GEN(dev_priv) >= 7)
#define HAS_IPS(dev_priv) (IS_HSW_ULT(dev_priv) || IS_BROADWELL(dev_priv))
@ -2570,7 +2582,7 @@ static inline unsigned int i915_sg_segment_size(void)
#define HAS_PCH_NOP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_NOP)
#define HAS_PCH_SPLIT(dev_priv) (INTEL_PCH_TYPE(dev_priv) != PCH_NONE)
#define HAS_GMCH_DISPLAY(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch_display)
#define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch)
#define HAS_LSPCON(dev_priv) (INTEL_GEN(dev_priv) >= 9)
@ -3305,6 +3317,20 @@ mkwrite_device_info(struct drm_i915_private *dev_priv)
return (struct intel_device_info *)INTEL_INFO(dev_priv);
}
static inline struct intel_sseu
intel_device_default_sseu(struct drm_i915_private *i915)
{
const struct sseu_dev_info *sseu = &RUNTIME_INFO(i915)->sseu;
struct intel_sseu value = {
.slice_mask = sseu->slice_mask,
.subslice_mask = sseu->subslice_mask[0],
.min_eus_per_subslice = sseu->max_eus_per_subslice,
.max_eus_per_subslice = sseu->max_eus_per_subslice,
};
return value;
}
/* modesetting */
extern void intel_modeset_init_hw(struct drm_device *dev);
extern int intel_modeset_init(struct drm_device *dev);

View File

@ -1681,6 +1681,16 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
return 0;
}
static inline bool
__vma_matches(struct vm_area_struct *vma, struct file *filp,
unsigned long addr, unsigned long size)
{
if (vma->vm_file != filp)
return false;
return vma->vm_start == addr && (vma->vm_end - vma->vm_start) == size;
}
/**
* i915_gem_mmap_ioctl - Maps the contents of an object, returning the address
* it is mapped to.
@ -1730,6 +1740,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
addr = vm_mmap(obj->base.filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
if (IS_ERR_VALUE(addr))
goto err;
if (args->flags & I915_MMAP_WC) {
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
@ -1739,23 +1752,28 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
return -EINTR;
}
vma = find_vma(mm, addr);
if (vma)
if (vma && __vma_matches(vma, obj->base.filp, addr, args->size))
vma->vm_page_prot =
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
else
addr = -ENOMEM;
up_write(&mm->mmap_sem);
if (IS_ERR_VALUE(addr))
goto err;
/* This may race, but that's ok, it only gets set */
WRITE_ONCE(obj->frontbuffer_ggtt_origin, ORIGIN_CPU);
}
i915_gem_object_put(obj);
if (IS_ERR((void *)addr))
return addr;
args->addr_ptr = (u64)addr;
return 0;
err:
i915_gem_object_put(obj);
return addr;
}
static unsigned int tile_row_pages(const struct drm_i915_gem_object *obj)
@ -3020,7 +3038,7 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915)
GEM_BUG_ON(i915->gt.active_requests);
for_each_engine(engine, i915, id) {
GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request));
GEM_BUG_ON(__i915_active_request_peek(&engine->timeline.last_request));
GEM_BUG_ON(engine->last_retired_context !=
to_intel_context(i915->kernel_context, engine));
}
@ -3266,7 +3284,7 @@ wait_for_timelines(struct drm_i915_private *i915,
list_for_each_entry(tl, &gt->active_list, link) {
struct i915_request *rq;
rq = i915_gem_active_get_unlocked(&tl->last_request);
rq = i915_active_request_get_unlocked(&tl->last_request);
if (!rq)
continue;
@ -4167,7 +4185,8 @@ out:
}
static void
frontbuffer_retire(struct i915_gem_active *active, struct i915_request *request)
frontbuffer_retire(struct i915_active_request *active,
struct i915_request *request)
{
struct drm_i915_gem_object *obj =
container_of(active, typeof(*obj), frontbuffer_write);
@ -4194,7 +4213,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
obj->resv = &obj->__builtin_resv;
obj->frontbuffer_ggtt_origin = ORIGIN_GTT;
init_request_active(&obj->frontbuffer_write, frontbuffer_retire);
i915_active_request_init(&obj->frontbuffer_write,
NULL, frontbuffer_retire);
obj->mm.madv = I915_MADV_WILLNEED;
INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN);

View File

@ -89,6 +89,7 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "i915_trace.h"
#include "intel_lrc_reg.h"
#include "intel_workarounds.h"
#define ALL_L3_SLICES(dev) (1 << NUM_L3_SLICES(dev)) - 1
@ -321,6 +322,15 @@ static u32 default_desc_template(const struct drm_i915_private *i915,
return desc;
}
static void intel_context_retire(struct i915_active_request *active,
struct i915_request *rq)
{
struct intel_context *ce =
container_of(active, typeof(*ce), active_tracker);
intel_context_unpin(ce);
}
void
intel_context_init(struct intel_context *ce,
struct i915_gem_context *ctx,
@ -330,6 +340,12 @@ intel_context_init(struct intel_context *ce,
INIT_LIST_HEAD(&ce->signal_link);
INIT_LIST_HEAD(&ce->signals);
/* Use the whole device by default */
ce->sseu = intel_device_default_sseu(ctx->i915);
i915_active_request_init(&ce->active_tracker,
NULL, intel_context_retire);
}
static struct i915_gem_context *
@ -653,8 +669,8 @@ last_request_on_engine(struct i915_timeline *timeline,
GEM_BUG_ON(timeline == &engine->timeline);
rq = i915_gem_active_raw(&timeline->last_request,
&engine->i915->drm.struct_mutex);
rq = i915_active_request_raw(&timeline->last_request,
&engine->i915->drm.struct_mutex);
if (rq && rq->engine == engine) {
GEM_TRACE("last request for %s on engine %s: %llx:%llu\n",
timeline->name, engine->name,
@ -847,6 +863,56 @@ out:
return 0;
}
static int get_sseu(struct i915_gem_context *ctx,
struct drm_i915_gem_context_param *args)
{
struct drm_i915_gem_context_param_sseu user_sseu;
struct intel_engine_cs *engine;
struct intel_context *ce;
int ret;
if (args->size == 0)
goto out;
else if (args->size < sizeof(user_sseu))
return -EINVAL;
if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
sizeof(user_sseu)))
return -EFAULT;
if (user_sseu.flags || user_sseu.rsvd)
return -EINVAL;
engine = intel_engine_lookup_user(ctx->i915,
user_sseu.engine_class,
user_sseu.engine_instance);
if (!engine)
return -EINVAL;
/* Only use for mutex here is to serialize get_param and set_param. */
ret = mutex_lock_interruptible(&ctx->i915->drm.struct_mutex);
if (ret)
return ret;
ce = to_intel_context(ctx, engine);
user_sseu.slice_mask = ce->sseu.slice_mask;
user_sseu.subslice_mask = ce->sseu.subslice_mask;
user_sseu.min_eus_per_subslice = ce->sseu.min_eus_per_subslice;
user_sseu.max_eus_per_subslice = ce->sseu.max_eus_per_subslice;
mutex_unlock(&ctx->i915->drm.struct_mutex);
if (copy_to_user(u64_to_user_ptr(args->value), &user_sseu,
sizeof(user_sseu)))
return -EFAULT;
out:
args->size = sizeof(user_sseu);
return 0;
}
int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@ -859,15 +925,17 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
if (!ctx)
return -ENOENT;
args->size = 0;
switch (args->param) {
case I915_CONTEXT_PARAM_BAN_PERIOD:
ret = -EINVAL;
break;
case I915_CONTEXT_PARAM_NO_ZEROMAP:
args->size = 0;
args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
break;
case I915_CONTEXT_PARAM_GTT_SIZE:
args->size = 0;
if (ctx->ppgtt)
args->value = ctx->ppgtt->vm.total;
else if (to_i915(dev)->mm.aliasing_ppgtt)
@ -876,14 +944,20 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
args->value = to_i915(dev)->ggtt.vm.total;
break;
case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
args->size = 0;
args->value = i915_gem_context_no_error_capture(ctx);
break;
case I915_CONTEXT_PARAM_BANNABLE:
args->size = 0;
args->value = i915_gem_context_is_bannable(ctx);
break;
case I915_CONTEXT_PARAM_PRIORITY:
args->size = 0;
args->value = ctx->sched.priority >> I915_USER_PRIORITY_SHIFT;
break;
case I915_CONTEXT_PARAM_SSEU:
ret = get_sseu(ctx, args);
break;
default:
ret = -EINVAL;
break;
@ -893,6 +967,281 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
return ret;
}
static int gen8_emit_rpcs_config(struct i915_request *rq,
struct intel_context *ce,
struct intel_sseu sseu)
{
u64 offset;
u32 *cs;
cs = intel_ring_begin(rq, 4);
if (IS_ERR(cs))
return PTR_ERR(cs);
offset = i915_ggtt_offset(ce->state) +
LRC_STATE_PN * PAGE_SIZE +
(CTX_R_PWR_CLK_STATE + 1) * 4;
*cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
*cs++ = lower_32_bits(offset);
*cs++ = upper_32_bits(offset);
*cs++ = gen8_make_rpcs(rq->i915, &sseu);
intel_ring_advance(rq, cs);
return 0;
}
static int
gen8_modify_rpcs_gpu(struct intel_context *ce,
struct intel_engine_cs *engine,
struct intel_sseu sseu)
{
struct drm_i915_private *i915 = engine->i915;
struct i915_request *rq, *prev;
intel_wakeref_t wakeref;
int ret;
GEM_BUG_ON(!ce->pin_count);
lockdep_assert_held(&i915->drm.struct_mutex);
/* Submitting requests etc needs the hw awake. */
wakeref = intel_runtime_pm_get(i915);
rq = i915_request_alloc(engine, i915->kernel_context);
if (IS_ERR(rq)) {
ret = PTR_ERR(rq);
goto out_put;
}
/* Queue this switch after all other activity by this context. */
prev = i915_active_request_raw(&ce->ring->timeline->last_request,
&i915->drm.struct_mutex);
if (prev && !i915_request_completed(prev)) {
ret = i915_request_await_dma_fence(rq, &prev->fence);
if (ret < 0)
goto out_add;
}
/* Order all following requests to be after. */
ret = i915_timeline_set_barrier(ce->ring->timeline, rq);
if (ret)
goto out_add;
ret = gen8_emit_rpcs_config(rq, ce, sseu);
if (ret)
goto out_add;
/*
* Guarantee context image and the timeline remains pinned until the
* modifying request is retired by setting the ce activity tracker.
*
* But we only need to take one pin on the account of it. Or in other
* words transfer the pinned ce object to tracked active request.
*/
if (!i915_active_request_isset(&ce->active_tracker))
__intel_context_pin(ce);
__i915_active_request_set(&ce->active_tracker, rq);
out_add:
i915_request_add(rq);
out_put:
intel_runtime_pm_put(i915, wakeref);
return ret;
}
static int
__i915_gem_context_reconfigure_sseu(struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct intel_sseu sseu)
{
struct intel_context *ce = to_intel_context(ctx, engine);
int ret = 0;
GEM_BUG_ON(INTEL_GEN(ctx->i915) < 8);
GEM_BUG_ON(engine->id != RCS);
/* Nothing to do if unmodified. */
if (!memcmp(&ce->sseu, &sseu, sizeof(sseu)))
return 0;
/*
* If context is not idle we have to submit an ordered request to modify
* its context image via the kernel context. Pristine and idle contexts
* will be configured on pinning.
*/
if (ce->pin_count)
ret = gen8_modify_rpcs_gpu(ce, engine, sseu);
if (!ret)
ce->sseu = sseu;
return ret;
}
static int
i915_gem_context_reconfigure_sseu(struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct intel_sseu sseu)
{
int ret;
ret = mutex_lock_interruptible(&ctx->i915->drm.struct_mutex);
if (ret)
return ret;
ret = __i915_gem_context_reconfigure_sseu(ctx, engine, sseu);
mutex_unlock(&ctx->i915->drm.struct_mutex);
return ret;
}
static int
user_to_context_sseu(struct drm_i915_private *i915,
const struct drm_i915_gem_context_param_sseu *user,
struct intel_sseu *context)
{
const struct sseu_dev_info *device = &RUNTIME_INFO(i915)->sseu;
/* No zeros in any field. */
if (!user->slice_mask || !user->subslice_mask ||
!user->min_eus_per_subslice || !user->max_eus_per_subslice)
return -EINVAL;
/* Max > min. */
if (user->max_eus_per_subslice < user->min_eus_per_subslice)
return -EINVAL;
/*
* Some future proofing on the types since the uAPI is wider than the
* current internal implementation.
*/
if (overflows_type(user->slice_mask, context->slice_mask) ||
overflows_type(user->subslice_mask, context->subslice_mask) ||
overflows_type(user->min_eus_per_subslice,
context->min_eus_per_subslice) ||
overflows_type(user->max_eus_per_subslice,
context->max_eus_per_subslice))
return -EINVAL;
/* Check validity against hardware. */
if (user->slice_mask & ~device->slice_mask)
return -EINVAL;
if (user->subslice_mask & ~device->subslice_mask[0])
return -EINVAL;
if (user->max_eus_per_subslice > device->max_eus_per_subslice)
return -EINVAL;
context->slice_mask = user->slice_mask;
context->subslice_mask = user->subslice_mask;
context->min_eus_per_subslice = user->min_eus_per_subslice;
context->max_eus_per_subslice = user->max_eus_per_subslice;
/* Part specific restrictions. */
if (IS_GEN(i915, 11)) {
unsigned int hw_s = hweight8(device->slice_mask);
unsigned int hw_ss_per_s = hweight8(device->subslice_mask[0]);
unsigned int req_s = hweight8(context->slice_mask);
unsigned int req_ss = hweight8(context->subslice_mask);
/*
* Only full subslice enablement is possible if more than one
* slice is turned on.
*/
if (req_s > 1 && req_ss != hw_ss_per_s)
return -EINVAL;
/*
* If more than four (SScount bitfield limit) subslices are
* requested then the number has to be even.
*/
if (req_ss > 4 && (req_ss & 1))
return -EINVAL;
/*
* If only one slice is enabled and subslice count is below the
* device full enablement, it must be at most half of the all
* available subslices.
*/
if (req_s == 1 && req_ss < hw_ss_per_s &&
req_ss > (hw_ss_per_s / 2))
return -EINVAL;
/* ABI restriction - VME use case only. */
/* All slices or one slice only. */
if (req_s != 1 && req_s != hw_s)
return -EINVAL;
/*
* Half subslices or full enablement only when one slice is
* enabled.
*/
if (req_s == 1 &&
(req_ss != hw_ss_per_s && req_ss != (hw_ss_per_s / 2)))
return -EINVAL;
/* No EU configuration changes. */
if ((user->min_eus_per_subslice !=
device->max_eus_per_subslice) ||
(user->max_eus_per_subslice !=
device->max_eus_per_subslice))
return -EINVAL;
}
return 0;
}
static int set_sseu(struct i915_gem_context *ctx,
struct drm_i915_gem_context_param *args)
{
struct drm_i915_private *i915 = ctx->i915;
struct drm_i915_gem_context_param_sseu user_sseu;
struct intel_engine_cs *engine;
struct intel_sseu sseu;
int ret;
if (args->size < sizeof(user_sseu))
return -EINVAL;
if (!IS_GEN(i915, 11))
return -ENODEV;
if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
sizeof(user_sseu)))
return -EFAULT;
if (user_sseu.flags || user_sseu.rsvd)
return -EINVAL;
engine = intel_engine_lookup_user(i915,
user_sseu.engine_class,
user_sseu.engine_instance);
if (!engine)
return -EINVAL;
/* Only render engine supports RPCS configuration. */
if (engine->class != RENDER_CLASS)
return -ENODEV;
ret = user_to_context_sseu(i915, &user_sseu, &sseu);
if (ret)
return ret;
ret = i915_gem_context_reconfigure_sseu(ctx, engine, sseu);
if (ret)
return ret;
args->size = sizeof(user_sseu);
return 0;
}
int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@ -955,7 +1304,9 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
I915_USER_PRIORITY(priority);
}
break;
case I915_CONTEXT_PARAM_SSEU:
ret = set_sseu(ctx, args);
break;
default:
ret = -EINVAL;
break;

View File

@ -31,6 +31,7 @@
#include "i915_gem.h"
#include "i915_scheduler.h"
#include "intel_device_info.h"
struct pid;
@ -53,6 +54,16 @@ struct intel_context_ops {
void (*destroy)(struct intel_context *ce);
};
/*
* Powergating configuration for a particular (context,engine).
*/
struct intel_sseu {
u8 slice_mask;
u8 subslice_mask;
u8 min_eus_per_subslice;
u8 max_eus_per_subslice;
};
/**
* struct i915_gem_context - client state
*
@ -172,7 +183,16 @@ struct i915_gem_context {
u64 lrc_desc;
int pin_count;
/**
* active_tracker: Active tracker for the external rq activity
* on this intel_context object.
*/
struct i915_active_request active_tracker;
const struct intel_context_ops *ops;
/** sseu: Control eu/slice partitioning */
struct intel_sseu sseu;
} __engine[I915_NUM_ENGINES];
/** ring_size: size for allocating the per-engine ring buffer */

View File

@ -753,6 +753,68 @@ static int eb_select_context(struct i915_execbuffer *eb)
return 0;
}
static struct i915_request *__eb_wait_for_ring(struct intel_ring *ring)
{
struct i915_request *rq;
/*
* Completely unscientific finger-in-the-air estimates for suitable
* maximum user request size (to avoid blocking) and then backoff.
*/
if (intel_ring_update_space(ring) >= PAGE_SIZE)
return NULL;
/*
* Find a request that after waiting upon, there will be at least half
* the ring available. The hysteresis allows us to compete for the
* shared ring and should mean that we sleep less often prior to
* claiming our resources, but not so long that the ring completely
* drains before we can submit our next request.
*/
list_for_each_entry(rq, &ring->request_list, ring_link) {
if (__intel_ring_space(rq->postfix,
ring->emit, ring->size) > ring->size / 2)
break;
}
if (&rq->ring_link == &ring->request_list)
return NULL; /* weird, we will check again later for real */
return i915_request_get(rq);
}
static int eb_wait_for_ring(const struct i915_execbuffer *eb)
{
const struct intel_context *ce;
struct i915_request *rq;
int ret = 0;
/*
* Apply a light amount of backpressure to prevent excessive hogs
* from blocking waiting for space whilst holding struct_mutex and
* keeping all of their resources pinned.
*/
ce = to_intel_context(eb->ctx, eb->engine);
if (!ce->ring) /* first use, assume empty! */
return 0;
rq = __eb_wait_for_ring(ce->ring);
if (rq) {
mutex_unlock(&eb->i915->drm.struct_mutex);
if (i915_request_wait(rq,
I915_WAIT_INTERRUPTIBLE,
MAX_SCHEDULE_TIMEOUT) < 0)
ret = -EINTR;
i915_request_put(rq);
mutex_lock(&eb->i915->drm.struct_mutex);
}
return ret;
}
static int eb_lookup_vmas(struct i915_execbuffer *eb)
{
struct radix_tree_root *handles_vma = &eb->ctx->handles_vma;
@ -2291,6 +2353,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
if (err)
goto err_rpm;
err = eb_wait_for_ring(&eb); /* may temporarily drop struct_mutex */
if (unlikely(err))
goto err_unlock;
err = eb_relocate(&eb);
if (err) {
/*
@ -2435,6 +2501,7 @@ err_batch_unpin:
err_vma:
if (eb.exec)
eb_release_vmas(&eb);
err_unlock:
mutex_unlock(&dev->struct_mutex);
err_rpm:
intel_runtime_pm_put(eb.i915, wakeref);

View File

@ -223,7 +223,7 @@ static int fence_update(struct drm_i915_fence_reg *fence,
i915_gem_object_get_tiling(vma->obj)))
return -EINVAL;
ret = i915_gem_active_retire(&vma->last_fence,
ret = i915_active_request_retire(&vma->last_fence,
&vma->obj->base.dev->struct_mutex);
if (ret)
return ret;
@ -232,7 +232,7 @@ static int fence_update(struct drm_i915_fence_reg *fence,
if (fence->vma) {
struct i915_vma *old = fence->vma;
ret = i915_gem_active_retire(&old->last_fence,
ret = i915_active_request_retire(&old->last_fence,
&old->obj->base.dev->struct_mutex);
if (ret)
return ret;

View File

@ -1917,14 +1917,13 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size)
if (!vma)
return ERR_PTR(-ENOMEM);
init_request_active(&vma->last_fence, NULL);
i915_active_init(i915, &vma->active, NULL);
INIT_ACTIVE_REQUEST(&vma->last_fence);
vma->vm = &ggtt->vm;
vma->ops = &pd_vma_ops;
vma->private = ppgtt;
vma->active = RB_ROOT;
vma->size = size;
vma->fence_size = size;
vma->flags = I915_VMA_GGTT;

View File

@ -175,7 +175,7 @@ struct drm_i915_gem_object {
atomic_t frontbuffer_bits;
unsigned int frontbuffer_ggtt_origin; /* write once */
struct i915_gem_active frontbuffer_write;
struct i915_active_request frontbuffer_write;
/** Current tiling stride for the object, if it's tiled. */
unsigned int tiling_and_stride;

View File

@ -1062,23 +1062,23 @@ i915_error_object_create(struct drm_i915_private *i915,
}
/* The error capture is special as tries to run underneath the normal
* locking rules - so we use the raw version of the i915_gem_active lookup.
* locking rules - so we use the raw version of the i915_active_request lookup.
*/
static inline u32
__active_get_seqno(struct i915_gem_active *active)
__active_get_seqno(struct i915_active_request *active)
{
struct i915_request *request;
request = __i915_gem_active_peek(active);
request = __i915_active_request_peek(active);
return request ? request->global_seqno : 0;
}
static inline int
__active_get_engine_id(struct i915_gem_active *active)
__active_get_engine_id(struct i915_active_request *active)
{
struct i915_request *request;
request = __i915_gem_active_peek(active);
request = __i915_active_request_peek(active);
return request ? request->engine->id : -1;
}

View File

@ -28,6 +28,7 @@
#include <drm/drm_drv.h>
#include "i915_active.h"
#include "i915_drv.h"
#include "i915_selftest.h"
@ -89,7 +90,7 @@
.num_pipes = 1, \
.display.has_overlay = 1, \
.display.overlay_needs_physical = 1, \
.display.has_gmch_display = 1, \
.display.has_gmch = 1, \
.gpu_reset_clobbers_display = true, \
.hws_needs_physical = 1, \
.unfenced_needs_alignment = 1, \
@ -130,7 +131,7 @@ static const struct intel_device_info intel_i865g_info = {
#define GEN3_FEATURES \
GEN(3), \
.num_pipes = 2, \
.display.has_gmch_display = 1, \
.display.has_gmch = 1, \
.gpu_reset_clobbers_display = true, \
.ring_mask = RENDER_RING, \
.has_snoop = true, \
@ -207,7 +208,7 @@ static const struct intel_device_info intel_pineview_info = {
GEN(4), \
.num_pipes = 2, \
.display.has_hotplug = 1, \
.display.has_gmch_display = 1, \
.display.has_gmch = 1, \
.gpu_reset_clobbers_display = true, \
.ring_mask = RENDER_RING, \
.has_snoop = true, \
@ -383,7 +384,7 @@ static const struct intel_device_info intel_valleyview_info = {
.num_pipes = 2,
.has_runtime_pm = 1,
.has_rc6 = 1,
.display.has_gmch_display = 1,
.display.has_gmch = 1,
.display.has_hotplug = 1,
.ppgtt = INTEL_PPGTT_FULL,
.has_snoop = true,
@ -475,7 +476,7 @@ static const struct intel_device_info intel_cherryview_info = {
.has_runtime_pm = 1,
.has_rc6 = 1,
.has_logical_ring_contexts = 1,
.display.has_gmch_display = 1,
.display.has_gmch = 1,
.ppgtt = INTEL_PPGTT_FULL,
.has_reset_engine = 1,
.has_snoop = true,
@ -800,6 +801,8 @@ static int __init i915_init(void)
bool use_kms = true;
int err;
i915_global_active_init();
err = i915_mock_selftests();
if (err)
return err > 0 ? 0 : err;
@ -831,6 +834,7 @@ static void __exit i915_exit(void)
return;
pci_unregister_driver(&i915_pci_driver);
i915_global_active_exit();
}
module_init(i915_init);

View File

@ -1677,6 +1677,11 @@ static void gen8_update_reg_state_unlocked(struct i915_gem_context *ctx,
CTX_REG(reg_state, state_offset, flex_regs[i], value);
}
CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE,
gen8_make_rpcs(dev_priv,
&to_intel_context(ctx,
dev_priv->engine[RCS])->sseu));
}
/*
@ -2098,21 +2103,21 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
if (ret)
goto err_lock;
stream->ops = &i915_oa_stream_ops;
dev_priv->perf.oa.exclusive_stream = stream;
ret = dev_priv->perf.oa.ops.enable_metric_set(stream);
if (ret) {
DRM_DEBUG("Unable to enable metric set\n");
goto err_enable;
}
stream->ops = &i915_oa_stream_ops;
dev_priv->perf.oa.exclusive_stream = stream;
mutex_unlock(&dev_priv->drm.struct_mutex);
return 0;
err_enable:
dev_priv->perf.oa.exclusive_stream = NULL;
dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
mutex_unlock(&dev_priv->drm.struct_mutex);

View File

@ -599,7 +599,8 @@ static void i915_pmu_enable(struct perf_event *event)
* Update the bitmask of enabled events and increment
* the event reference counter.
*/
GEM_BUG_ON(bit >= I915_PMU_MASK_BITS);
BUILD_BUG_ON(ARRAY_SIZE(i915->pmu.enable_count) != I915_PMU_MASK_BITS);
GEM_BUG_ON(bit >= ARRAY_SIZE(i915->pmu.enable_count));
GEM_BUG_ON(i915->pmu.enable_count[bit] == ~0);
i915->pmu.enable |= BIT_ULL(bit);
i915->pmu.enable_count[bit]++;
@ -620,11 +621,16 @@ static void i915_pmu_enable(struct perf_event *event)
engine = intel_engine_lookup_user(i915,
engine_event_class(event),
engine_event_instance(event));
GEM_BUG_ON(!engine);
engine->pmu.enable |= BIT(sample);
GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS);
BUILD_BUG_ON(ARRAY_SIZE(engine->pmu.enable_count) !=
I915_ENGINE_SAMPLE_COUNT);
BUILD_BUG_ON(ARRAY_SIZE(engine->pmu.sample) !=
I915_ENGINE_SAMPLE_COUNT);
GEM_BUG_ON(sample >= ARRAY_SIZE(engine->pmu.enable_count));
GEM_BUG_ON(sample >= ARRAY_SIZE(engine->pmu.sample));
GEM_BUG_ON(engine->pmu.enable_count[sample] == ~0);
engine->pmu.enable |= BIT(sample);
engine->pmu.enable_count[sample]++;
}
@ -654,9 +660,11 @@ static void i915_pmu_disable(struct perf_event *event)
engine = intel_engine_lookup_user(i915,
engine_event_class(event),
engine_event_instance(event));
GEM_BUG_ON(!engine);
GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS);
GEM_BUG_ON(sample >= ARRAY_SIZE(engine->pmu.enable_count));
GEM_BUG_ON(sample >= ARRAY_SIZE(engine->pmu.sample));
GEM_BUG_ON(engine->pmu.enable_count[sample] == 0);
/*
* Decrement the reference count and clear the enabled
* bitmask when the last listener on an event goes away.
@ -665,7 +673,7 @@ static void i915_pmu_disable(struct perf_event *event)
engine->pmu.enable &= ~BIT(sample);
}
GEM_BUG_ON(bit >= I915_PMU_MASK_BITS);
GEM_BUG_ON(bit >= ARRAY_SIZE(i915->pmu.enable_count));
GEM_BUG_ON(i915->pmu.enable_count[bit] == 0);
/*
* Decrement the reference count and clear the enabled

View File

@ -31,6 +31,8 @@ enum {
((1 << I915_PMU_SAMPLE_BITS) + \
(I915_PMU_LAST + 1 - __I915_PMU_OTHER(0)))
#define I915_ENGINE_SAMPLE_COUNT (I915_SAMPLE_SEMA + 1)
struct i915_pmu_sample {
u64 cur;
};

View File

@ -6000,7 +6000,7 @@ enum {
#define PLANE_WM_EN (1 << 31)
#define PLANE_WM_LINES_SHIFT 14
#define PLANE_WM_LINES_MASK 0x1f
#define PLANE_WM_BLOCKS_MASK 0x3ff
#define PLANE_WM_BLOCKS_MASK 0x7ff /* skl+: 10 bits, icl+ 11 bits */
#define _CUR_WM_0(pipe) _PIPE(pipe, _CUR_WM_A_0, _CUR_WM_B_0)
#define CUR_WM(pipe, level) _MMIO(_CUR_WM_0(pipe) + ((4) * (level)))
@ -6784,8 +6784,7 @@ enum {
#define _PLANE_BUF_CFG_1_B 0x7127c
#define _PLANE_BUF_CFG_2_B 0x7137c
#define SKL_DDB_ENTRY_MASK 0x3FF
#define ICL_DDB_ENTRY_MASK 0x7FF
#define DDB_ENTRY_MASK 0x7FF /* skl+: 10 bits, icl+ 11 bits */
#define DDB_ENTRY_END_SHIFT 16
#define _PLANE_BUF_CFG_1(pipe) \
_PIPE(pipe, _PLANE_BUF_CFG_1_A, _PLANE_BUF_CFG_1_B)
@ -7618,6 +7617,7 @@ enum {
#define _PIPEB_CHICKEN 0x71038
#define _PIPEC_CHICKEN 0x72038
#define PER_PIXEL_ALPHA_BYPASS_EN (1 << 7)
#define PM_FILL_MAINTAIN_DBUF_FULLNESS (1 << 0)
#define PIPE_CHICKEN(pipe) _MMIO_PIPE(pipe, _PIPEA_CHICKEN,\
_PIPEB_CHICKEN)

View File

@ -29,6 +29,7 @@
#include <linux/sched/signal.h>
#include "i915_drv.h"
#include "i915_active.h"
#include "i915_reset.h"
static const char *i915_fence_get_driver_name(struct dma_fence *fence)
@ -125,12 +126,6 @@ static void unreserve_gt(struct drm_i915_private *i915)
i915_gem_park(i915);
}
void i915_gem_retire_noop(struct i915_gem_active *active,
struct i915_request *request)
{
/* Space left intentionally blank */
}
static void advance_ring(struct i915_request *request)
{
struct intel_ring *ring = request->ring;
@ -244,7 +239,7 @@ static void __retire_engine_upto(struct intel_engine_cs *engine,
static void i915_request_retire(struct i915_request *request)
{
struct i915_gem_active *active, *next;
struct i915_active_request *active, *next;
GEM_TRACE("%s fence %llx:%lld, global=%d, current %d:%d\n",
request->engine->name,
@ -278,10 +273,10 @@ static void i915_request_retire(struct i915_request *request)
* we may spend an inordinate amount of time simply handling
* the retirement of requests and processing their callbacks.
* Of which, this loop itself is particularly hot due to the
* cache misses when jumping around the list of i915_gem_active.
* So we try to keep this loop as streamlined as possible and
* also prefetch the next i915_gem_active to try and hide
* the likely cache miss.
* cache misses when jumping around the list of
* i915_active_request. So we try to keep this loop as
* streamlined as possible and also prefetch the next
* i915_active_request to try and hide the likely cache miss.
*/
prefetchw(next);
@ -526,6 +521,11 @@ out:
return kmem_cache_alloc(ce->gem_context->i915->requests, GFP_KERNEL);
}
static int add_timeline_barrier(struct i915_request *rq)
{
return i915_request_await_active_request(rq, &rq->timeline->barrier);
}
/**
* i915_request_alloc - allocate a request structure
*
@ -582,7 +582,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
* We use RCU to look up requests in flight. The lookups may
* race with the request being allocated from the slab freelist.
* That is the request we are writing to here, may be in the process
* of being read by __i915_gem_active_get_rcu(). As such,
* of being read by __i915_active_request_get_rcu(). As such,
* we have to be very careful when overwriting the contents. During
* the RCU lookup, we change chase the request->engine pointer,
* read the request->global_seqno and increment the reference count.
@ -668,6 +668,10 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
*/
rq->head = rq->ring->emit;
ret = add_timeline_barrier(rq);
if (ret)
goto err_unwind;
ret = engine->request_alloc(rq);
if (ret)
goto err_unwind;
@ -920,8 +924,8 @@ void i915_request_add(struct i915_request *request)
* see a more recent value in the hws than we are tracking.
*/
prev = i915_gem_active_raw(&timeline->last_request,
&request->i915->drm.struct_mutex);
prev = i915_active_request_raw(&timeline->last_request,
&request->i915->drm.struct_mutex);
if (prev && !i915_request_completed(prev)) {
i915_sw_fence_await_sw_fence(&request->submit, &prev->submit,
&request->submitq);
@ -937,7 +941,7 @@ void i915_request_add(struct i915_request *request)
spin_unlock_irq(&timeline->lock);
GEM_BUG_ON(timeline->seqno != request->fence.seqno);
i915_gem_active_set(&timeline->last_request, request);
__i915_active_request_set(&timeline->last_request, request);
list_add_tail(&request->ring_link, &ring->request_list);
if (list_is_first(&request->ring_link, &ring->request_list)) {
@ -968,7 +972,7 @@ void i915_request_add(struct i915_request *request)
* Allow interactive/synchronous clients to jump ahead of
* the bulk clients. (FQ_CODEL)
*/
if (!prev || i915_request_completed(prev))
if (list_empty(&request->sched.signalers_list))
attr.priority |= I915_PRIORITY_NEWCLIENT;
engine->schedule(request, &attr);

View File

@ -403,387 +403,4 @@ static inline void i915_request_mark_complete(struct i915_request *rq)
void i915_retire_requests(struct drm_i915_private *i915);
/*
* We treat requests as fences. This is not be to confused with our
* "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
* We use the fences to synchronize access from the CPU with activity on the
* GPU, for example, we should not rewrite an object's PTE whilst the GPU
* is reading them. We also track fences at a higher level to provide
* implicit synchronisation around GEM objects, e.g. set-domain will wait
* for outstanding GPU rendering before marking the object ready for CPU
* access, or a pageflip will wait until the GPU is complete before showing
* the frame on the scanout.
*
* In order to use a fence, the object must track the fence it needs to
* serialise with. For example, GEM objects want to track both read and
* write access so that we can perform concurrent read operations between
* the CPU and GPU engines, as well as waiting for all rendering to
* complete, or waiting for the last GPU user of a "fence register". The
* object then embeds a #i915_gem_active to track the most recent (in
* retirement order) request relevant for the desired mode of access.
* The #i915_gem_active is updated with i915_gem_active_set() to track the
* most recent fence request, typically this is done as part of
* i915_vma_move_to_active().
*
* When the #i915_gem_active completes (is retired), it will
* signal its completion to the owner through a callback as well as mark
* itself as idle (i915_gem_active.request == NULL). The owner
* can then perform any action, such as delayed freeing of an active
* resource including itself.
*/
struct i915_gem_active;
typedef void (*i915_gem_retire_fn)(struct i915_gem_active *,
struct i915_request *);
struct i915_gem_active {
struct i915_request __rcu *request;
struct list_head link;
i915_gem_retire_fn retire;
};
void i915_gem_retire_noop(struct i915_gem_active *,
struct i915_request *request);
/**
* init_request_active - prepares the activity tracker for use
* @active - the active tracker
* @func - a callback when then the tracker is retired (becomes idle),
* can be NULL
*
* init_request_active() prepares the embedded @active struct for use as
* an activity tracker, that is for tracking the last known active request
* associated with it. When the last request becomes idle, when it is retired
* after completion, the optional callback @func is invoked.
*/
static inline void
init_request_active(struct i915_gem_active *active,
i915_gem_retire_fn retire)
{
RCU_INIT_POINTER(active->request, NULL);
INIT_LIST_HEAD(&active->link);
active->retire = retire ?: i915_gem_retire_noop;
}
/**
* i915_gem_active_set - updates the tracker to watch the current request
* @active - the active tracker
* @request - the request to watch
*
* i915_gem_active_set() watches the given @request for completion. Whilst
* that @request is busy, the @active reports busy. When that @request is
* retired, the @active tracker is updated to report idle.
*/
static inline void
i915_gem_active_set(struct i915_gem_active *active,
struct i915_request *request)
{
list_move(&active->link, &request->active_list);
rcu_assign_pointer(active->request, request);
}
/**
* i915_gem_active_set_retire_fn - updates the retirement callback
* @active - the active tracker
* @fn - the routine called when the request is retired
* @mutex - struct_mutex used to guard retirements
*
* i915_gem_active_set_retire_fn() updates the function pointer that
* is called when the final request associated with the @active tracker
* is retired.
*/
static inline void
i915_gem_active_set_retire_fn(struct i915_gem_active *active,
i915_gem_retire_fn fn,
struct mutex *mutex)
{
lockdep_assert_held(mutex);
active->retire = fn ?: i915_gem_retire_noop;
}
static inline struct i915_request *
__i915_gem_active_peek(const struct i915_gem_active *active)
{
/*
* Inside the error capture (running with the driver in an unknown
* state), we want to bend the rules slightly (a lot).
*
* Work is in progress to make it safer, in the meantime this keeps
* the known issue from spamming the logs.
*/
return rcu_dereference_protected(active->request, 1);
}
/**
* i915_gem_active_raw - return the active request
* @active - the active tracker
*
* i915_gem_active_raw() returns the current request being tracked, or NULL.
* It does not obtain a reference on the request for the caller, so the caller
* must hold struct_mutex.
*/
static inline struct i915_request *
i915_gem_active_raw(const struct i915_gem_active *active, struct mutex *mutex)
{
return rcu_dereference_protected(active->request,
lockdep_is_held(mutex));
}
/**
* i915_gem_active_peek - report the active request being monitored
* @active - the active tracker
*
* i915_gem_active_peek() returns the current request being tracked if
* still active, or NULL. It does not obtain a reference on the request
* for the caller, so the caller must hold struct_mutex.
*/
static inline struct i915_request *
i915_gem_active_peek(const struct i915_gem_active *active, struct mutex *mutex)
{
struct i915_request *request;
request = i915_gem_active_raw(active, mutex);
if (!request || i915_request_completed(request))
return NULL;
return request;
}
/**
* i915_gem_active_get - return a reference to the active request
* @active - the active tracker
*
* i915_gem_active_get() returns a reference to the active request, or NULL
* if the active tracker is idle. The caller must hold struct_mutex.
*/
static inline struct i915_request *
i915_gem_active_get(const struct i915_gem_active *active, struct mutex *mutex)
{
return i915_request_get(i915_gem_active_peek(active, mutex));
}
/**
* __i915_gem_active_get_rcu - return a reference to the active request
* @active - the active tracker
*
* __i915_gem_active_get() returns a reference to the active request, or NULL
* if the active tracker is idle. The caller must hold the RCU read lock, but
* the returned pointer is safe to use outside of RCU.
*/
static inline struct i915_request *
__i915_gem_active_get_rcu(const struct i915_gem_active *active)
{
/*
* Performing a lockless retrieval of the active request is super
* tricky. SLAB_TYPESAFE_BY_RCU merely guarantees that the backing
* slab of request objects will not be freed whilst we hold the
* RCU read lock. It does not guarantee that the request itself
* will not be freed and then *reused*. Viz,
*
* Thread A Thread B
*
* rq = active.request
* retire(rq) -> free(rq);
* (rq is now first on the slab freelist)
* active.request = NULL
*
* rq = new submission on a new object
* ref(rq)
*
* To prevent the request from being reused whilst the caller
* uses it, we take a reference like normal. Whilst acquiring
* the reference we check that it is not in a destroyed state
* (refcnt == 0). That prevents the request being reallocated
* whilst the caller holds on to it. To check that the request
* was not reallocated as we acquired the reference we have to
* check that our request remains the active request across
* the lookup, in the same manner as a seqlock. The visibility
* of the pointer versus the reference counting is controlled
* by using RCU barriers (rcu_dereference and rcu_assign_pointer).
*
* In the middle of all that, we inspect whether the request is
* complete. Retiring is lazy so the request may be completed long
* before the active tracker is updated. Querying whether the
* request is complete is far cheaper (as it involves no locked
* instructions setting cachelines to exclusive) than acquiring
* the reference, so we do it first. The RCU read lock ensures the
* pointer dereference is valid, but does not ensure that the
* seqno nor HWS is the right one! However, if the request was
* reallocated, that means the active tracker's request was complete.
* If the new request is also complete, then both are and we can
* just report the active tracker is idle. If the new request is
* incomplete, then we acquire a reference on it and check that
* it remained the active request.
*
* It is then imperative that we do not zero the request on
* reallocation, so that we can chase the dangling pointers!
* See i915_request_alloc().
*/
do {
struct i915_request *request;
request = rcu_dereference(active->request);
if (!request || i915_request_completed(request))
return NULL;
/*
* An especially silly compiler could decide to recompute the
* result of i915_request_completed, more specifically
* re-emit the load for request->fence.seqno. A race would catch
* a later seqno value, which could flip the result from true to
* false. Which means part of the instructions below might not
* be executed, while later on instructions are executed. Due to
* barriers within the refcounting the inconsistency can't reach
* past the call to i915_request_get_rcu, but not executing
* that while still executing i915_request_put() creates
* havoc enough. Prevent this with a compiler barrier.
*/
barrier();
request = i915_request_get_rcu(request);
/*
* What stops the following rcu_access_pointer() from occurring
* before the above i915_request_get_rcu()? If we were
* to read the value before pausing to get the reference to
* the request, we may not notice a change in the active
* tracker.
*
* The rcu_access_pointer() is a mere compiler barrier, which
* means both the CPU and compiler are free to perform the
* memory read without constraint. The compiler only has to
* ensure that any operations after the rcu_access_pointer()
* occur afterwards in program order. This means the read may
* be performed earlier by an out-of-order CPU, or adventurous
* compiler.
*
* The atomic operation at the heart of
* i915_request_get_rcu(), see dma_fence_get_rcu(), is
* atomic_inc_not_zero() which is only a full memory barrier
* when successful. That is, if i915_request_get_rcu()
* returns the request (and so with the reference counted
* incremented) then the following read for rcu_access_pointer()
* must occur after the atomic operation and so confirm
* that this request is the one currently being tracked.
*
* The corresponding write barrier is part of
* rcu_assign_pointer().
*/
if (!request || request == rcu_access_pointer(active->request))
return rcu_pointer_handoff(request);
i915_request_put(request);
} while (1);
}
/**
* i915_gem_active_get_unlocked - return a reference to the active request
* @active - the active tracker
*
* i915_gem_active_get_unlocked() returns a reference to the active request,
* or NULL if the active tracker is idle. The reference is obtained under RCU,
* so no locking is required by the caller.
*
* The reference should be freed with i915_request_put().
*/
static inline struct i915_request *
i915_gem_active_get_unlocked(const struct i915_gem_active *active)
{
struct i915_request *request;
rcu_read_lock();
request = __i915_gem_active_get_rcu(active);
rcu_read_unlock();
return request;
}
/**
* i915_gem_active_isset - report whether the active tracker is assigned
* @active - the active tracker
*
* i915_gem_active_isset() returns true if the active tracker is currently
* assigned to a request. Due to the lazy retiring, that request may be idle
* and this may report stale information.
*/
static inline bool
i915_gem_active_isset(const struct i915_gem_active *active)
{
return rcu_access_pointer(active->request);
}
/**
* i915_gem_active_wait - waits until the request is completed
* @active - the active request on which to wait
* @flags - how to wait
* @timeout - how long to wait at most
* @rps - userspace client to charge for a waitboost
*
* i915_gem_active_wait() waits until the request is completed before
* returning, without requiring any locks to be held. Note that it does not
* retire any requests before returning.
*
* This function relies on RCU in order to acquire the reference to the active
* request without holding any locks. See __i915_gem_active_get_rcu() for the
* glory details on how that is managed. Once the reference is acquired, we
* can then wait upon the request, and afterwards release our reference,
* free of any locking.
*
* This function wraps i915_request_wait(), see it for the full details on
* the arguments.
*
* Returns 0 if successful, or a negative error code.
*/
static inline int
i915_gem_active_wait(const struct i915_gem_active *active, unsigned int flags)
{
struct i915_request *request;
long ret = 0;
request = i915_gem_active_get_unlocked(active);
if (request) {
ret = i915_request_wait(request, flags, MAX_SCHEDULE_TIMEOUT);
i915_request_put(request);
}
return ret < 0 ? ret : 0;
}
/**
* i915_gem_active_retire - waits until the request is retired
* @active - the active request on which to wait
*
* i915_gem_active_retire() waits until the request is completed,
* and then ensures that at least the retirement handler for this
* @active tracker is called before returning. If the @active
* tracker is idle, the function returns immediately.
*/
static inline int __must_check
i915_gem_active_retire(struct i915_gem_active *active,
struct mutex *mutex)
{
struct i915_request *request;
long ret;
request = i915_gem_active_raw(active, mutex);
if (!request)
return 0;
ret = i915_request_wait(request,
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
MAX_SCHEDULE_TIMEOUT);
if (ret < 0)
return ret;
list_del_init(&active->link);
RCU_INIT_POINTER(active->request, NULL);
active->retire(active, request);
return 0;
}
#define for_each_active(mask, idx) \
for (; mask ? idx = ffs(mask) - 1, 1 : 0; mask &= ~BIT(idx))
#endif /* I915_REQUEST_H */

View File

@ -862,7 +862,7 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
struct i915_request *rq;
long timeout;
rq = i915_gem_active_get_unlocked(&tl->last_request);
rq = i915_active_request_get_unlocked(&tl->last_request);
if (!rq)
continue;

View File

@ -86,7 +86,7 @@ int i915_save_state(struct drm_i915_private *dev_priv)
} else if (IS_GEN(dev_priv, 2)) {
for (i = 0; i < 7; i++)
dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i));
} else if (HAS_GMCH_DISPLAY(dev_priv)) {
} else if (HAS_GMCH(dev_priv)) {
for (i = 0; i < 16; i++) {
dev_priv->regfile.saveSWF0[i] = I915_READ(SWF0(i));
dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i));
@ -131,7 +131,7 @@ int i915_restore_state(struct drm_i915_private *dev_priv)
} else if (IS_GEN(dev_priv, 2)) {
for (i = 0; i < 7; i++)
I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]);
} else if (HAS_GMCH_DISPLAY(dev_priv)) {
} else if (HAS_GMCH(dev_priv)) {
for (i = 0; i < 16; i++) {
I915_WRITE(SWF0(i), dev_priv->regfile.saveSWF0[i]);
I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]);

View File

@ -163,7 +163,8 @@ int i915_timeline_init(struct drm_i915_private *i915,
spin_lock_init(&timeline->lock);
init_request_active(&timeline->last_request, NULL);
INIT_ACTIVE_REQUEST(&timeline->barrier);
INIT_ACTIVE_REQUEST(&timeline->last_request);
INIT_LIST_HEAD(&timeline->requests);
i915_syncmap_init(&timeline->sync);
@ -235,6 +236,7 @@ void i915_timeline_fini(struct i915_timeline *timeline)
{
GEM_BUG_ON(timeline->pin_count);
GEM_BUG_ON(!list_empty(&timeline->requests));
GEM_BUG_ON(i915_active_request_isset(&timeline->barrier));
i915_syncmap_free(&timeline->sync);
hwsp_free(timeline);

View File

@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/kref.h>
#include "i915_active.h"
#include "i915_request.h"
#include "i915_syncmap.h"
#include "i915_utils.h"
@ -58,10 +59,10 @@ struct i915_timeline {
/* Contains an RCU guarded pointer to the last request. No reference is
* held to the request, users must carefully acquire a reference to
* the request using i915_gem_active_get_request_rcu(), or hold the
* the request using i915_active_request_get_request_rcu(), or hold the
* struct_mutex.
*/
struct i915_gem_active last_request;
struct i915_active_request last_request;
/**
* We track the most recent seqno that we wait on in every context so
@ -74,6 +75,16 @@ struct i915_timeline {
*/
struct i915_syncmap *sync;
/**
* Barrier provides the ability to serialize ordering between different
* timelines.
*
* Users can call i915_timeline_set_barrier which will make all
* subsequent submissions to this timeline be executed only after the
* barrier has been completed.
*/
struct i915_active_request barrier;
struct list_head link;
const char *name;
struct drm_i915_private *i915;
@ -155,4 +166,19 @@ void i915_timelines_init(struct drm_i915_private *i915);
void i915_timelines_park(struct drm_i915_private *i915);
void i915_timelines_fini(struct drm_i915_private *i915);
/**
* i915_timeline_set_barrier - orders submission between different timelines
* @timeline: timeline to set the barrier on
* @rq: request after which new submissions can proceed
*
* Sets the passed in request as the serialization point for all subsequent
* submissions on @timeline. Subsequent requests will not be submitted to GPU
* until the barrier has been completed.
*/
static inline int
i915_timeline_set_barrier(struct i915_timeline *tl, struct i915_request *rq)
{
return i915_active_request_set(&tl->barrier, rq);
}
#endif

View File

@ -63,21 +63,22 @@ static void vma_print_allocator(struct i915_vma *vma, const char *reason)
#endif
struct i915_vma_active {
struct i915_gem_active base;
struct i915_vma *vma;
struct rb_node node;
u64 timeline;
};
static void
__i915_vma_retire(struct i915_vma *vma, struct i915_request *rq)
static void obj_bump_mru(struct drm_i915_gem_object *obj)
{
struct drm_i915_gem_object *obj = vma->obj;
struct drm_i915_private *i915 = to_i915(obj->base.dev);
GEM_BUG_ON(!i915_vma_is_active(vma));
if (--vma->active_count)
return;
spin_lock(&i915->mm.obj_lock);
if (obj->bind_count)
list_move_tail(&obj->mm.link, &i915->mm.bound_list);
spin_unlock(&i915->mm.obj_lock);
obj->mm.dirty = true; /* be paranoid */
}
static void __i915_vma_retire(struct i915_active *ref)
{
struct i915_vma *vma = container_of(ref, typeof(*vma), active);
struct drm_i915_gem_object *obj = vma->obj;
GEM_BUG_ON(!i915_gem_object_is_active(obj));
if (--obj->active_count)
@ -90,16 +91,12 @@ __i915_vma_retire(struct i915_vma *vma, struct i915_request *rq)
reservation_object_unlock(obj->resv);
}
/* Bump our place on the bound list to keep it roughly in LRU order
/*
* Bump our place on the bound list to keep it roughly in LRU order
* so that we don't steal from recently used but inactive objects
* (unless we are forced to ofc!)
*/
spin_lock(&rq->i915->mm.obj_lock);
if (obj->bind_count)
list_move_tail(&obj->mm.link, &rq->i915->mm.bound_list);
spin_unlock(&rq->i915->mm.obj_lock);
obj->mm.dirty = true; /* be paranoid */
obj_bump_mru(obj);
if (i915_gem_object_has_active_reference(obj)) {
i915_gem_object_clear_active_reference(obj);
@ -107,21 +104,6 @@ __i915_vma_retire(struct i915_vma *vma, struct i915_request *rq)
}
}
static void
i915_vma_retire(struct i915_gem_active *base, struct i915_request *rq)
{
struct i915_vma_active *active =
container_of(base, typeof(*active), base);
__i915_vma_retire(active->vma, rq);
}
static void
i915_vma_last_retire(struct i915_gem_active *base, struct i915_request *rq)
{
__i915_vma_retire(container_of(base, struct i915_vma, last_active), rq);
}
static struct i915_vma *
vma_create(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
@ -137,10 +119,9 @@ vma_create(struct drm_i915_gem_object *obj,
if (vma == NULL)
return ERR_PTR(-ENOMEM);
vma->active = RB_ROOT;
i915_active_init(vm->i915, &vma->active, __i915_vma_retire);
INIT_ACTIVE_REQUEST(&vma->last_fence);
init_request_active(&vma->last_active, i915_vma_last_retire);
init_request_active(&vma->last_fence, NULL);
vma->vm = vm;
vma->ops = &vm->vma_ops;
vma->obj = obj;
@ -823,12 +804,11 @@ void i915_vma_reopen(struct i915_vma *vma)
static void __i915_vma_destroy(struct i915_vma *vma)
{
struct drm_i915_private *i915 = vma->vm->i915;
struct i915_vma_active *iter, *n;
GEM_BUG_ON(vma->node.allocated);
GEM_BUG_ON(vma->fence);
GEM_BUG_ON(i915_gem_active_isset(&vma->last_fence));
GEM_BUG_ON(i915_active_request_isset(&vma->last_fence));
mutex_lock(&vma->vm->mutex);
list_del(&vma->vm_link);
@ -843,10 +823,7 @@ static void __i915_vma_destroy(struct i915_vma *vma)
spin_unlock(&obj->vma.lock);
}
rbtree_postorder_for_each_entry_safe(iter, n, &vma->active, node) {
GEM_BUG_ON(i915_gem_active_isset(&iter->base));
kfree(iter);
}
i915_active_fini(&vma->active);
kmem_cache_free(i915->vmas, vma);
}
@ -931,104 +908,15 @@ static void export_fence(struct i915_vma *vma,
reservation_object_unlock(resv);
}
static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx)
{
struct i915_vma_active *active;
struct rb_node **p, *parent;
struct i915_request *old;
/*
* We track the most recently used timeline to skip a rbtree search
* for the common case, under typical loads we never need the rbtree
* at all. We can reuse the last_active slot if it is empty, that is
* after the previous activity has been retired, or if the active
* matches the current timeline.
*
* Note that we allow the timeline to be active simultaneously in
* the rbtree and the last_active cache. We do this to avoid having
* to search and replace the rbtree element for a new timeline, with
* the cost being that we must be aware that the vma may be retired
* twice for the same timeline (as the older rbtree element will be
* retired before the new request added to last_active).
*/
old = i915_gem_active_raw(&vma->last_active,
&vma->vm->i915->drm.struct_mutex);
if (!old || old->fence.context == idx)
goto out;
/* Move the currently active fence into the rbtree */
idx = old->fence.context;
parent = NULL;
p = &vma->active.rb_node;
while (*p) {
parent = *p;
active = rb_entry(parent, struct i915_vma_active, node);
if (active->timeline == idx)
goto replace;
if (active->timeline < idx)
p = &parent->rb_right;
else
p = &parent->rb_left;
}
active = kmalloc(sizeof(*active), GFP_KERNEL);
/* kmalloc may retire the vma->last_active request (thanks shrinker)! */
if (unlikely(!i915_gem_active_raw(&vma->last_active,
&vma->vm->i915->drm.struct_mutex))) {
kfree(active);
goto out;
}
if (unlikely(!active))
return ERR_PTR(-ENOMEM);
init_request_active(&active->base, i915_vma_retire);
active->vma = vma;
active->timeline = idx;
rb_link_node(&active->node, parent, p);
rb_insert_color(&active->node, &vma->active);
replace:
/*
* Overwrite the previous active slot in the rbtree with last_active,
* leaving last_active zeroed. If the previous slot is still active,
* we must be careful as we now only expect to receive one retire
* callback not two, and so much undo the active counting for the
* overwritten slot.
*/
if (i915_gem_active_isset(&active->base)) {
/* Retire ourselves from the old rq->active_list */
__list_del_entry(&active->base.link);
vma->active_count--;
GEM_BUG_ON(!vma->active_count);
}
GEM_BUG_ON(list_empty(&vma->last_active.link));
list_replace_init(&vma->last_active.link, &active->base.link);
active->base.request = fetch_and_zero(&vma->last_active.request);
out:
return &vma->last_active;
}
int i915_vma_move_to_active(struct i915_vma *vma,
struct i915_request *rq,
unsigned int flags)
{
struct drm_i915_gem_object *obj = vma->obj;
struct i915_gem_active *active;
lockdep_assert_held(&rq->i915->drm.struct_mutex);
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
active = active_instance(vma, rq->fence.context);
if (IS_ERR(active))
return PTR_ERR(active);
/*
* Add a reference if we're newly entering the active list.
* The order in which we add operations to the retirement queue is
@ -1037,9 +925,15 @@ int i915_vma_move_to_active(struct i915_vma *vma,
* add the active reference first and queue for it to be dropped
* *last*.
*/
if (!i915_gem_active_isset(active) && !vma->active_count++)
if (!vma->active.count)
obj->active_count++;
i915_gem_active_set(active, rq);
if (unlikely(i915_active_ref(&vma->active, rq->fence.context, rq))) {
if (!vma->active.count)
obj->active_count--;
return -ENOMEM;
}
GEM_BUG_ON(!i915_vma_is_active(vma));
GEM_BUG_ON(!obj->active_count);
@ -1048,14 +942,14 @@ int i915_vma_move_to_active(struct i915_vma *vma,
obj->write_domain = I915_GEM_DOMAIN_RENDER;
if (intel_fb_obj_invalidate(obj, ORIGIN_CS))
i915_gem_active_set(&obj->frontbuffer_write, rq);
__i915_active_request_set(&obj->frontbuffer_write, rq);
obj->read_domains = 0;
}
obj->read_domains |= I915_GEM_GPU_DOMAINS;
if (flags & EXEC_OBJECT_NEEDS_FENCE)
i915_gem_active_set(&vma->last_fence, rq);
__i915_active_request_set(&vma->last_fence, rq);
export_fence(vma, rq, flags);
return 0;
@ -1073,8 +967,6 @@ int i915_vma_unbind(struct i915_vma *vma)
*/
might_sleep();
if (i915_vma_is_active(vma)) {
struct i915_vma_active *active, *n;
/*
* When a closed VMA is retired, it is unbound - eek.
* In order to prevent it from being recursively closed,
@ -1090,21 +982,12 @@ int i915_vma_unbind(struct i915_vma *vma)
*/
__i915_vma_pin(vma);
ret = i915_gem_active_retire(&vma->last_active,
&vma->vm->i915->drm.struct_mutex);
ret = i915_active_wait(&vma->active);
if (ret)
goto unpin;
rbtree_postorder_for_each_entry_safe(active, n,
&vma->active, node) {
ret = i915_gem_active_retire(&active->base,
&vma->vm->i915->drm.struct_mutex);
if (ret)
goto unpin;
}
ret = i915_gem_active_retire(&vma->last_fence,
&vma->vm->i915->drm.struct_mutex);
ret = i915_active_request_retire(&vma->last_fence,
&vma->vm->i915->drm.struct_mutex);
unpin:
__i915_vma_unpin(vma);
if (ret)

View File

@ -34,6 +34,7 @@
#include "i915_gem_fence_reg.h"
#include "i915_gem_object.h"
#include "i915_active.h"
#include "i915_request.h"
enum i915_cache_level;
@ -108,10 +109,8 @@ struct i915_vma {
#define I915_VMA_USERFAULT BIT(I915_VMA_USERFAULT_BIT)
#define I915_VMA_GGTT_WRITE BIT(15)
unsigned int active_count;
struct rb_root active;
struct i915_gem_active last_active;
struct i915_gem_active last_fence;
struct i915_active active;
struct i915_active_request last_fence;
/**
* Support different GGTT views into the same object.
@ -154,9 +153,9 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
void i915_vma_unpin_and_release(struct i915_vma **p_vma, unsigned int flags);
#define I915_VMA_RELEASE_MAP BIT(0)
static inline bool i915_vma_is_active(struct i915_vma *vma)
static inline bool i915_vma_is_active(const struct i915_vma *vma)
{
return vma->active_count;
return !i915_active_is_idle(&vma->active);
}
int __must_check i915_vma_move_to_active(struct i915_vma *vma,

View File

@ -74,12 +74,12 @@
#define ILK_CSC_COEFF_1_0 \
((7 << 12) | ILK_CSC_COEFF_FP(CTM_COEFF_1_0, 8))
static bool lut_is_legacy(struct drm_property_blob *lut)
static bool lut_is_legacy(const struct drm_property_blob *lut)
{
return drm_color_lut_size(lut) == LEGACY_LUT_LENGTH;
}
static bool crtc_state_is_legacy_gamma(struct intel_crtc_state *crtc_state)
static bool crtc_state_is_legacy_gamma(const struct intel_crtc_state *crtc_state)
{
return !crtc_state->base.degamma_lut &&
!crtc_state->base.ctm &&
@ -115,8 +115,8 @@ static u64 *ctm_mult_by_limited(u64 *result, const u64 *input)
static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *crtc)
{
int pipe = crtc->pipe;
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
@ -137,13 +137,14 @@ static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *crtc)
I915_WRITE(PIPE_CSC_MODE(pipe), 0);
}
static void ilk_load_csc_matrix(struct intel_crtc_state *crtc_state)
static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
int i, pipe = crtc->pipe;
u16 coeffs[9] = { 0, };
bool limited_color_range = false;
enum pipe pipe = crtc->pipe;
u16 coeffs[9] = {};
int i;
/*
* FIXME if there's a gamma LUT after the CSC, we should
@ -256,16 +257,16 @@ static void ilk_load_csc_matrix(struct intel_crtc_state *crtc_state)
/*
* Set up the pipe CSC unit on CherryView.
*/
static void cherryview_load_csc_matrix(struct intel_crtc_state *crtc_state)
static void cherryview_load_csc_matrix(const struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc_state->base.crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
int pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
u32 mode;
if (crtc_state->base.ctm) {
struct drm_color_ctm *ctm = crtc_state->base.ctm->data;
u16 coeffs[9] = { 0, };
const struct drm_color_ctm *ctm = crtc_state->base.ctm->data;
u16 coeffs[9] = {};
int i;
for (i = 0; i < ARRAY_SIZE(coeffs); i++) {
@ -303,25 +304,16 @@ static void cherryview_load_csc_matrix(struct intel_crtc_state *crtc_state)
I915_WRITE(CGM_PIPE_MODE(pipe), mode);
}
void intel_color_set_csc(struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc_state->base.crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
if (dev_priv->display.load_csc_matrix)
dev_priv->display.load_csc_matrix(crtc_state);
}
/* Loads the legacy palette/gamma unit for the CRTC. */
static void i9xx_load_luts_internal(struct intel_crtc_state *crtc_state,
struct drm_property_blob *blob)
static void i9xx_load_luts_internal(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
int i;
if (HAS_GMCH_DISPLAY(dev_priv)) {
if (HAS_GMCH(dev_priv)) {
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
assert_dsi_pll_enabled(dev_priv);
else
@ -329,14 +321,15 @@ static void i9xx_load_luts_internal(struct intel_crtc_state *crtc_state,
}
if (blob) {
struct drm_color_lut *lut = blob->data;
const struct drm_color_lut *lut = blob->data;
for (i = 0; i < 256; i++) {
u32 word =
(drm_color_lut_extract(lut[i].red, 8) << 16) |
(drm_color_lut_extract(lut[i].green, 8) << 8) |
drm_color_lut_extract(lut[i].blue, 8);
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
I915_WRITE(PALETTE(pipe, i), word);
else
I915_WRITE(LGC_PALETTE(pipe, i), word);
@ -345,7 +338,7 @@ static void i9xx_load_luts_internal(struct intel_crtc_state *crtc_state,
for (i = 0; i < 256; i++) {
u32 word = (i << 16) | (i << 8) | i;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
I915_WRITE(PALETTE(pipe, i), word);
else
I915_WRITE(LGC_PALETTE(pipe, i), word);
@ -353,48 +346,34 @@ static void i9xx_load_luts_internal(struct intel_crtc_state *crtc_state,
}
}
static void i9xx_load_luts(struct intel_crtc_state *crtc_state)
static void i9xx_load_luts(const struct intel_crtc_state *crtc_state)
{
i9xx_load_luts_internal(crtc_state, crtc_state->base.gamma_lut);
}
/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
static void haswell_load_luts(struct intel_crtc_state *crtc_state)
static void hsw_color_commit(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
bool reenable_ips = false;
/*
* Workaround : Do not read or write the pipe palette/gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
*/
if (IS_HASWELL(dev_priv) && crtc_state->ips_enabled &&
(crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
hsw_disable_ips(crtc_state);
reenable_ips = true;
}
I915_WRITE(GAMMA_MODE(crtc->pipe), crtc_state->gamma_mode);
crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
I915_WRITE(GAMMA_MODE(crtc->pipe), GAMMA_MODE_MODE_8BIT);
i9xx_load_luts(crtc_state);
if (reenable_ips)
hsw_enable_ips(crtc_state);
ilk_load_csc_matrix(crtc_state);
}
static void bdw_load_degamma_lut(struct intel_crtc_state *crtc_state)
static void bdw_load_degamma_lut(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_property_blob *degamma_lut = crtc_state->base.degamma_lut;
u32 i, lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size;
enum pipe pipe = crtc->pipe;
I915_WRITE(PREC_PAL_INDEX(pipe),
PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT);
if (crtc_state->base.degamma_lut) {
struct drm_color_lut *lut = crtc_state->base.degamma_lut->data;
if (degamma_lut) {
const struct drm_color_lut *lut = degamma_lut->data;
for (i = 0; i < lut_size; i++) {
u32 word =
@ -414,11 +393,13 @@ static void bdw_load_degamma_lut(struct intel_crtc_state *crtc_state)
}
}
static void bdw_load_gamma_lut(struct intel_crtc_state *crtc_state, u32 offset)
static void bdw_load_gamma_lut(const struct intel_crtc_state *crtc_state, u32 offset)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_property_blob *gamma_lut = crtc_state->base.gamma_lut;
u32 i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
enum pipe pipe = crtc->pipe;
WARN_ON(offset & ~PAL_PREC_INDEX_VALUE_MASK);
@ -427,8 +408,8 @@ static void bdw_load_gamma_lut(struct intel_crtc_state *crtc_state, u32 offset)
PAL_PREC_AUTO_INCREMENT |
offset);
if (crtc_state->base.gamma_lut) {
struct drm_color_lut *lut = crtc_state->base.gamma_lut->data;
if (gamma_lut) {
const struct drm_color_lut *lut = gamma_lut->data;
for (i = 0; i < lut_size; i++) {
u32 word =
@ -462,35 +443,32 @@ static void bdw_load_gamma_lut(struct intel_crtc_state *crtc_state, u32 offset)
}
/* Loads the palette/gamma unit for the CRTC on Broadwell+. */
static void broadwell_load_luts(struct intel_crtc_state *crtc_state)
static void broadwell_load_luts(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
if (crtc_state_is_legacy_gamma(crtc_state)) {
haswell_load_luts(crtc_state);
return;
i9xx_load_luts(crtc_state);
} else {
bdw_load_degamma_lut(crtc_state);
bdw_load_gamma_lut(crtc_state,
INTEL_INFO(dev_priv)->color.degamma_lut_size);
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
I915_WRITE(PREC_PAL_INDEX(pipe), 0);
}
bdw_load_degamma_lut(crtc_state);
bdw_load_gamma_lut(crtc_state,
INTEL_INFO(dev_priv)->color.degamma_lut_size);
crtc_state->gamma_mode = GAMMA_MODE_MODE_SPLIT;
I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_SPLIT);
POSTING_READ(GAMMA_MODE(pipe));
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
I915_WRITE(PREC_PAL_INDEX(pipe), 0);
}
static void glk_load_degamma_lut(struct intel_crtc_state *crtc_state)
static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
const u32 lut_size = 33;
u32 i;
@ -517,48 +495,49 @@ static void glk_load_degamma_lut(struct intel_crtc_state *crtc_state)
I915_WRITE(PRE_CSC_GAMC_DATA(pipe), (1 << 16));
}
static void glk_load_luts(struct intel_crtc_state *crtc_state)
static void glk_load_luts(const struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc_state->base.crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
enum pipe pipe = to_intel_crtc(crtc_state->base.crtc)->pipe;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
glk_load_degamma_lut(crtc_state);
if (crtc_state_is_legacy_gamma(crtc_state)) {
haswell_load_luts(crtc_state);
return;
i9xx_load_luts(crtc_state);
} else {
bdw_load_gamma_lut(crtc_state, 0);
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
I915_WRITE(PREC_PAL_INDEX(pipe), 0);
}
bdw_load_gamma_lut(crtc_state, 0);
crtc_state->gamma_mode = GAMMA_MODE_MODE_10BIT;
I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_10BIT);
POSTING_READ(GAMMA_MODE(pipe));
}
/* Loads the palette/gamma unit for the CRTC on CherryView. */
static void cherryview_load_luts(struct intel_crtc_state *crtc_state)
static void cherryview_load_luts(const struct intel_crtc_state *crtc_state)
{
struct drm_crtc *crtc = crtc_state->base.crtc;
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
enum pipe pipe = to_intel_crtc(crtc)->pipe;
struct drm_color_lut *lut;
u32 i, lut_size;
u32 word0, word1;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_property_blob *gamma_lut = crtc_state->base.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->base.degamma_lut;
enum pipe pipe = crtc->pipe;
cherryview_load_csc_matrix(crtc_state);
if (crtc_state_is_legacy_gamma(crtc_state)) {
/* Turn off degamma/gamma on CGM block. */
I915_WRITE(CGM_PIPE_MODE(pipe),
(crtc_state->base.ctm ? CGM_PIPE_MODE_CSC : 0));
i9xx_load_luts_internal(crtc_state, crtc_state->base.gamma_lut);
i9xx_load_luts_internal(crtc_state, gamma_lut);
return;
}
if (crtc_state->base.degamma_lut) {
lut = crtc_state->base.degamma_lut->data;
lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size;
if (degamma_lut) {
const struct drm_color_lut *lut = degamma_lut->data;
int i, lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size;
for (i = 0; i < lut_size; i++) {
u32 word0, word1;
/* Write LUT in U0.14 format. */
word0 =
(drm_color_lut_extract(lut[i].green, 14) << 16) |
@ -570,10 +549,13 @@ static void cherryview_load_luts(struct intel_crtc_state *crtc_state)
}
}
if (crtc_state->base.gamma_lut) {
lut = crtc_state->base.gamma_lut->data;
lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
if (gamma_lut) {
const struct drm_color_lut *lut = gamma_lut->data;
int i, lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
for (i = 0; i < lut_size; i++) {
u32 word0, word1;
/* Write LUT in U0.10 format. */
word0 =
(drm_color_lut_extract(lut[i].green, 10) << 16) |
@ -585,11 +567,6 @@ static void cherryview_load_luts(struct intel_crtc_state *crtc_state)
}
}
I915_WRITE(CGM_PIPE_MODE(pipe),
(crtc_state->base.ctm ? CGM_PIPE_MODE_CSC : 0) |
(crtc_state->base.degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) |
(crtc_state->base.gamma_lut ? CGM_PIPE_MODE_GAMMA : 0));
/*
* Also program a linear LUT in the legacy block (behind the
* CGM block).
@ -597,14 +574,21 @@ static void cherryview_load_luts(struct intel_crtc_state *crtc_state)
i9xx_load_luts_internal(crtc_state, NULL);
}
void intel_color_load_luts(struct intel_crtc_state *crtc_state)
void intel_color_load_luts(const struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc_state->base.crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
dev_priv->display.load_luts(crtc_state);
}
void intel_color_commit(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
if (dev_priv->display.color_commit)
dev_priv->display.color_commit(crtc_state);
}
static int check_lut_size(const struct drm_property_blob *lut, int expected)
{
int len;
@ -625,6 +609,8 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected)
int intel_color_check(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
const struct drm_property_blob *gamma_lut = crtc_state->base.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->base.degamma_lut;
int gamma_length, degamma_length;
u32 gamma_tests, degamma_tests;
@ -634,17 +620,25 @@ int intel_color_check(struct intel_crtc_state *crtc_state)
gamma_tests = INTEL_INFO(dev_priv)->color.gamma_lut_tests;
/* Always allow legacy gamma LUT with no further checking. */
if (crtc_state_is_legacy_gamma(crtc_state))
if (crtc_state_is_legacy_gamma(crtc_state)) {
crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
return 0;
}
if (check_lut_size(crtc_state->base.degamma_lut, degamma_length) ||
check_lut_size(crtc_state->base.gamma_lut, gamma_length))
if (check_lut_size(degamma_lut, degamma_length) ||
check_lut_size(gamma_lut, gamma_length))
return -EINVAL;
if (drm_color_lut_check(crtc_state->base.degamma_lut, degamma_tests) ||
drm_color_lut_check(crtc_state->base.gamma_lut, gamma_tests))
if (drm_color_lut_check(degamma_lut, degamma_tests) ||
drm_color_lut_check(gamma_lut, gamma_tests))
return -EINVAL;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
crtc_state->gamma_mode = GAMMA_MODE_MODE_10BIT;
else if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
crtc_state->gamma_mode = GAMMA_MODE_MODE_SPLIT;
else
crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
return 0;
}
@ -656,18 +650,17 @@ void intel_color_init(struct intel_crtc *crtc)
drm_mode_crtc_set_gamma_size(&crtc->base, 256);
if (IS_CHERRYVIEW(dev_priv)) {
dev_priv->display.load_csc_matrix = cherryview_load_csc_matrix;
dev_priv->display.load_luts = cherryview_load_luts;
} else if (IS_HASWELL(dev_priv)) {
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
dev_priv->display.load_luts = haswell_load_luts;
dev_priv->display.load_luts = i9xx_load_luts;
dev_priv->display.color_commit = hsw_color_commit;
} else if (IS_BROADWELL(dev_priv) || IS_GEN9_BC(dev_priv) ||
IS_BROXTON(dev_priv)) {
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
dev_priv->display.load_luts = broadwell_load_luts;
dev_priv->display.color_commit = hsw_color_commit;
} else if (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) {
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
dev_priv->display.load_luts = glk_load_luts;
dev_priv->display.color_commit = hsw_color_commit;
} else {
dev_priv->display.load_luts = i9xx_load_luts;
}

View File

@ -115,7 +115,7 @@ enum intel_ppgtt {
func(has_ddi); \
func(has_dp_mst); \
func(has_fbc); \
func(has_gmch_display); \
func(has_gmch); \
func(has_hotplug); \
func(has_ipc); \
func(has_overlay); \

View File

@ -1805,7 +1805,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
* a plane. On ILK+ the pipe PLLs are integrated, so we don't
* need the check.
*/
if (HAS_GMCH_DISPLAY(dev_priv)) {
if (HAS_GMCH(dev_priv)) {
if (intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
assert_dsi_pll_enabled(dev_priv);
else
@ -2094,7 +2094,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
* complicated than this. For example, Cherryview appears quite
* happy to scanout from anywhere within its global aperture.
*/
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
pinctl |= PIN_MAPPABLE;
vma = i915_gem_object_pin_to_display_plane(obj,
@ -3195,7 +3195,7 @@ i9xx_plane_max_stride(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
if (!HAS_GMCH_DISPLAY(dev_priv)) {
if (!HAS_GMCH(dev_priv)) {
return 32*1024;
} else if (INTEL_GEN(dev_priv) >= 4) {
if (modifier == I915_FORMAT_MOD_X_TILED)
@ -3215,21 +3215,13 @@ i9xx_plane_max_stride(struct intel_plane *plane,
}
}
static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
const struct drm_framebuffer *fb = plane_state->base.fb;
unsigned int rotation = plane_state->base.rotation;
u32 dspcntr;
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dspcntr = 0;
dspcntr = DISPLAY_PLANE_ENABLE | DISPPLANE_GAMMA_ENABLE;
if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
dspcntr |= DISPPLANE_GAMMA_ENABLE;
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
@ -3237,6 +3229,24 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
if (INTEL_GEN(dev_priv) < 5)
dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
return dspcntr;
}
static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
unsigned int rotation = plane_state->base.rotation;
u32 dspcntr;
dspcntr = DISPLAY_PLANE_ENABLE;
if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
switch (fb->format->format) {
case DRM_FORMAT_C8:
dspcntr |= DISPPLANE_8BPP;
@ -3364,11 +3374,13 @@ static void i9xx_update_plane(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
u32 linear_offset;
u32 dspcntr = plane_state->ctl;
int x = plane_state->color_plane[0].x;
int y = plane_state->color_plane[0].y;
unsigned long irqflags;
u32 dspaddr_offset;
u32 dspcntr;
dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
@ -3428,10 +3440,23 @@ static void i9xx_disable_plane(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
unsigned long irqflags;
u32 dspcntr;
/*
* DSPCNTR pipe gamma enable on g4x+ and pipe csc
* enable on ilk+ affect the pipe bottom color as
* well, so we must configure them even if the plane
* is disabled.
*
* On pre-g4x there is no way to gamma correct the
* pipe bottom color but we'll keep on doing this
* anyway.
*/
dspcntr = i9xx_plane_ctl_crtc(crtc_state);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
I915_WRITE_FW(DSPCNTR(i9xx_plane), 0);
I915_WRITE_FW(DSPCNTR(i9xx_plane), dspcntr);
if (INTEL_GEN(dev_priv) >= 4)
I915_WRITE_FW(DSPSURF(i9xx_plane), 0);
else
@ -3668,6 +3693,20 @@ static u32 cnl_plane_ctl_flip(unsigned int reflect)
return 0;
}
u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
u32 plane_ctl = 0;
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
return plane_ctl;
plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE;
plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
return plane_ctl;
}
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
@ -3682,10 +3721,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
plane_ctl |= skl_plane_ctl_alpha(plane_state);
plane_ctl |=
PLANE_CTL_PIPE_GAMMA_ENABLE |
PLANE_CTL_PIPE_CSC_ENABLE |
PLANE_CTL_PLANE_GAMMA_DISABLE;
plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709;
@ -3710,19 +3746,27 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
return plane_ctl;
}
u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
u32 plane_color_ctl = 0;
if (INTEL_GEN(dev_priv) >= 11)
return plane_color_ctl;
plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
return plane_color_ctl;
}
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
u32 plane_color_ctl = 0;
if (INTEL_GEN(dev_priv) < 11) {
plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
}
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
@ -3771,7 +3815,7 @@ __intel_display_resume(struct drm_device *dev,
}
/* ignore any reset values/BIOS leftovers in the WM registers */
if (!HAS_GMCH_DISPLAY(to_i915(dev)))
if (!HAS_GMCH(to_i915(dev)))
to_intel_atomic_state(state)->skip_intermediate_wm = true;
ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
@ -3896,6 +3940,30 @@ unlock:
clear_bit(I915_RESET_MODESET, &dev_priv->gpu_error.flags);
}
static void icl_set_pipe_chicken(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
u32 tmp;
tmp = I915_READ(PIPE_CHICKEN(pipe));
/*
* Display WA #1153: icl
* enable hardware to bypass the alpha math
* and rounding for per-pixel values 00 and 0xff
*/
tmp |= PER_PIXEL_ALPHA_BYPASS_EN;
/*
* W/A for underruns with linear/X-tiled with
* WM1+ disabled.
*/
tmp |= PM_FILL_MAINTAIN_DBUF_FULLNESS;
I915_WRITE(PIPE_CHICKEN(pipe), tmp);
}
static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_state,
const struct intel_crtc_state *new_crtc_state)
{
@ -3940,6 +4008,9 @@ static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_sta
I915_WRITE(SKL_BOTTOM_COLOR(crtc->pipe),
SKL_BOTTOM_COLOR_GAMMA_ENABLE |
SKL_BOTTOM_COLOR_CSC_ENABLE);
if (INTEL_GEN(dev_priv) >= 11)
icl_set_pipe_chicken(crtc);
}
static void intel_fdi_normal_train(struct intel_crtc *crtc)
@ -5294,7 +5365,7 @@ intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
* event which is after the vblank start event, so we need to have a
* wait-for-vblank between disabling the plane and the pipe.
*/
if (HAS_GMCH_DISPLAY(dev_priv) &&
if (HAS_GMCH(dev_priv) &&
intel_set_memory_cxsr(dev_priv, false))
intel_wait_for_vblank(dev_priv, pipe);
}
@ -5302,24 +5373,54 @@ intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
static bool hsw_pre_update_disable_ips(const struct intel_crtc_state *old_crtc_state,
const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
if (!old_crtc_state->ips_enabled)
return false;
if (needs_modeset(&new_crtc_state->base))
return true;
/*
* Workaround : Do not read or write the pipe palette/gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
*
* Disable IPS before we program the LUT.
*/
if (IS_HASWELL(dev_priv) &&
(new_crtc_state->base.color_mgmt_changed ||
new_crtc_state->update_pipe) &&
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
return true;
return !new_crtc_state->ips_enabled;
}
static bool hsw_post_update_enable_ips(const struct intel_crtc_state *old_crtc_state,
const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
if (!new_crtc_state->ips_enabled)
return false;
if (needs_modeset(&new_crtc_state->base))
return true;
/*
* Workaround : Do not read or write the pipe palette/gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
*
* Re-enable IPS after the LUT has been programmed.
*/
if (IS_HASWELL(dev_priv) &&
(new_crtc_state->base.color_mgmt_changed ||
new_crtc_state->update_pipe) &&
new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
return true;
/*
* We can't read out IPS on broadwell, assume the worst and
* forcibly enable IPS on the first fastset.
@ -5431,7 +5532,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
* event which is after the vblank start event, so we need to have a
* wait-for-vblank between disabling the plane and the pipe.
*/
if (HAS_GMCH_DISPLAY(dev_priv) && old_crtc_state->base.active &&
if (HAS_GMCH(dev_priv) && old_crtc_state->base.active &&
pipe_config->disable_cxsr && intel_set_memory_cxsr(dev_priv, false))
intel_wait_for_vblank(dev_priv, crtc->pipe);
@ -5708,6 +5809,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
* clocks enabled
*/
intel_color_load_luts(pipe_config);
intel_color_commit(pipe_config);
if (dev_priv->display.initial_watermarks != NULL)
dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
@ -5782,7 +5884,6 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
bool psl_clkgate_wa;
u32 pipe_chicken;
if (WARN_ON(intel_crtc->active))
return;
@ -5818,8 +5919,6 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
haswell_set_pipemisc(pipe_config);
intel_color_set_csc(pipe_config);
intel_crtc->active = true;
/* Display WA #1180: WaDisableScalarClockGating: glk, cnl */
@ -5838,17 +5937,10 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
* clocks enabled
*/
intel_color_load_luts(pipe_config);
intel_color_commit(pipe_config);
/*
* Display WA #1153: enable hardware to bypass the alpha math
* and rounding for per-pixel values 00 and 0xff
*/
if (INTEL_GEN(dev_priv) >= 11) {
pipe_chicken = I915_READ(PIPE_CHICKEN(pipe));
if (!(pipe_chicken & PER_PIXEL_ALPHA_BYPASS_EN))
I915_WRITE_FW(PIPE_CHICKEN(pipe),
pipe_chicken | PER_PIXEL_ALPHA_BYPASS_EN);
}
if (INTEL_GEN(dev_priv) >= 11)
icl_set_pipe_chicken(intel_crtc);
intel_ddi_set_pipe_settings(pipe_config);
if (!transcoder_is_dsi(cpu_transcoder))
@ -6183,8 +6275,6 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
i9xx_set_pipeconf(pipe_config);
intel_color_set_csc(pipe_config);
intel_crtc->active = true;
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
@ -6204,6 +6294,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
i9xx_pfit_enable(pipe_config);
intel_color_load_luts(pipe_config);
intel_color_commit(pipe_config);
dev_priv->display.initial_watermarks(old_intel_state,
pipe_config);
@ -6260,6 +6351,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
i9xx_pfit_enable(pipe_config);
intel_color_load_luts(pipe_config);
intel_color_commit(pipe_config);
if (dev_priv->display.initial_watermarks != NULL)
dev_priv->display.initial_watermarks(old_intel_state,
@ -6705,7 +6797,7 @@ static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
/* FIXME calculate proper pipe pixel rate for GMCH pfit */
crtc_state->pixel_rate =
crtc_state->base.adjusted_mode.crtc_clock;
@ -9814,7 +9906,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
base += plane_state->color_plane[0].offset;
/* ILK+ do this automagically */
if (HAS_GMCH_DISPLAY(dev_priv) &&
if (HAS_GMCH(dev_priv) &&
plane_state->base.rotation & DRM_MODE_ROTATE_180)
base += (plane_state->base.crtc_h *
plane_state->base.crtc_w - 1) * fb->format->cpp[0];
@ -9927,11 +10019,15 @@ i845_cursor_max_stride(struct intel_plane *plane,
return 2048;
}
static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
return CURSOR_GAMMA_ENABLE;
}
static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
return CURSOR_ENABLE |
CURSOR_GAMMA_ENABLE |
CURSOR_FORMAT_ARGB |
CURSOR_STRIDE(plane_state->color_plane[0].stride);
}
@ -10001,7 +10097,9 @@ static void i845_update_cursor(struct intel_plane *plane,
unsigned int width = plane_state->base.crtc_w;
unsigned int height = plane_state->base.crtc_h;
cntl = plane_state->ctl;
cntl = plane_state->ctl |
i845_cursor_ctl_crtc(crtc_state);
size = (height << 12) | width;
base = intel_cursor_base(plane_state);
@ -10068,27 +10166,36 @@ i9xx_cursor_max_stride(struct intel_plane *plane,
return plane->base.dev->mode_config.cursor_width * 4;
}
static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 cntl = 0;
if (INTEL_GEN(dev_priv) >= 11)
return cntl;
cntl |= MCURSOR_GAMMA_ENABLE;
if (HAS_DDI(dev_priv))
cntl |= MCURSOR_PIPE_CSC_ENABLE;
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
return cntl;
}
static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
u32 cntl = 0;
if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
if (INTEL_GEN(dev_priv) <= 10) {
cntl |= MCURSOR_GAMMA_ENABLE;
if (HAS_DDI(dev_priv))
cntl |= MCURSOR_PIPE_CSC_ENABLE;
}
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
switch (plane_state->base.crtc_w) {
case 64:
cntl |= MCURSOR_MODE_64_ARGB_AX;
@ -10213,7 +10320,8 @@ static void i9xx_update_cursor(struct intel_plane *plane,
unsigned long irqflags;
if (plane_state && plane_state->base.visible) {
cntl = plane_state->ctl;
cntl = plane_state->ctl |
i9xx_cursor_ctl_crtc(crtc_state);
if (plane_state->base.crtc_h != plane_state->base.crtc_w)
fbc_ctl = CUR_FBC_CTL_EN | (plane_state->base.crtc_h - 1);
@ -11045,7 +11153,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
int ret;
bool mode_changed = needs_modeset(crtc_state);
if (mode_changed && !crtc_state->active)
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv) &&
mode_changed && !crtc_state->active)
pipe_config->update_wm_post = true;
if (mode_changed && crtc_state->enable &&
@ -11057,7 +11166,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
return ret;
}
if (crtc_state->color_mgmt_changed) {
if (mode_changed || crtc_state->color_mgmt_changed) {
ret = intel_color_check(pipe_config);
if (ret)
return ret;
@ -11356,7 +11465,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->scaler_state.scaler_users,
pipe_config->scaler_state.scaler_id);
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
pipe_config->gmch_pfit.control,
pipe_config->gmch_pfit.pgm_ratios,
@ -11468,44 +11577,38 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
return ret;
}
static void
static int
clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv =
to_i915(crtc_state->base.crtc->dev);
struct intel_crtc_scaler_state scaler_state;
struct intel_dpll_hw_state dpll_hw_state;
struct intel_shared_dpll *shared_dpll;
struct intel_crtc_wm_state wm_state;
bool force_thru, ips_force_disable;
struct intel_crtc_state *saved_state;
saved_state = kzalloc(sizeof(*saved_state), GFP_KERNEL);
if (!saved_state)
return -ENOMEM;
/* FIXME: before the switch to atomic started, a new pipe_config was
* kzalloc'd. Code that depends on any field being zero should be
* fixed, so that the crtc_state can be safely duplicated. For now,
* only fields that are know to not cause problems are preserved. */
scaler_state = crtc_state->scaler_state;
shared_dpll = crtc_state->shared_dpll;
dpll_hw_state = crtc_state->dpll_hw_state;
force_thru = crtc_state->pch_pfit.force_thru;
ips_force_disable = crtc_state->ips_force_disable;
saved_state->scaler_state = crtc_state->scaler_state;
saved_state->shared_dpll = crtc_state->shared_dpll;
saved_state->dpll_hw_state = crtc_state->dpll_hw_state;
saved_state->pch_pfit.force_thru = crtc_state->pch_pfit.force_thru;
saved_state->ips_force_disable = crtc_state->ips_force_disable;
if (IS_G4X(dev_priv) ||
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
wm_state = crtc_state->wm;
saved_state->wm = crtc_state->wm;
/* Keep base drm_crtc_state intact, only clear our extended struct */
BUILD_BUG_ON(offsetof(struct intel_crtc_state, base));
memset(&crtc_state->base + 1, 0,
memcpy(&crtc_state->base + 1, &saved_state->base + 1,
sizeof(*crtc_state) - sizeof(crtc_state->base));
crtc_state->scaler_state = scaler_state;
crtc_state->shared_dpll = shared_dpll;
crtc_state->dpll_hw_state = dpll_hw_state;
crtc_state->pch_pfit.force_thru = force_thru;
crtc_state->ips_force_disable = ips_force_disable;
if (IS_G4X(dev_priv) ||
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
crtc_state->wm = wm_state;
kfree(saved_state);
return 0;
}
static int
@ -11520,7 +11623,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
int i;
bool retry = true;
clear_intel_crtc_state(pipe_config);
ret = clear_intel_crtc_state(pipe_config);
if (ret)
return ret;
pipe_config->cpu_transcoder =
(enum transcoder) to_intel_crtc(crtc)->pipe;
@ -13096,7 +13201,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
/* FIXME unify this for all platforms */
if (!new_crtc_state->active &&
!HAS_GMCH_DISPLAY(dev_priv) &&
!HAS_GMCH(dev_priv) &&
dev_priv->display.initial_watermarks)
dev_priv->display.initial_watermarks(intel_state,
new_intel_crtc_state);
@ -13150,6 +13255,16 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
*/
drm_atomic_helper_wait_for_flip_done(dev, state);
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
new_intel_crtc_state = to_intel_crtc_state(new_crtc_state);
if (new_crtc_state->active &&
!needs_modeset(new_crtc_state) &&
(new_intel_crtc_state->base.color_mgmt_changed ||
new_intel_crtc_state->update_pipe))
intel_color_load_luts(new_intel_crtc_state);
}
/*
* Now that the vblank has passed, we can go ahead and program the
* optimal watermarks on platforms that need two-step watermark
@ -13665,19 +13780,16 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
bool modeset = needs_modeset(&intel_cstate->base);
if (!modeset &&
(intel_cstate->base.color_mgmt_changed ||
intel_cstate->update_pipe)) {
intel_color_set_csc(intel_cstate);
intel_color_load_luts(intel_cstate);
}
/* Perform vblank evasion around commit operation */
intel_pipe_update_start(intel_cstate);
if (modeset)
goto out;
if (intel_cstate->base.color_mgmt_changed ||
intel_cstate->update_pipe)
intel_color_commit(intel_cstate);
if (intel_cstate->update_pipe)
intel_update_pipe_config(old_intel_cstate, intel_cstate);
else if (INTEL_GEN(dev_priv) >= 9)
@ -15074,7 +15186,7 @@ retry:
* intermediate watermarks (since we don't trust the current
* watermarks).
*/
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
intel_state->skip_intermediate_wm = true;
ret = intel_atomic_check(dev, state);
@ -15315,7 +15427,7 @@ int intel_modeset_init(struct drm_device *dev)
* Note that we need to do this after reconstructing the BIOS fb's
* since the watermark calculation done here will use pstate->fb.
*/
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
sanitize_watermarks(dev);
/*
@ -15524,7 +15636,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
if (crtc_state->base.active && !intel_crtc_has_encoders(crtc))
intel_crtc_disable_noatomic(&crtc->base, ctx);
if (crtc_state->base.active || HAS_GMCH_DISPLAY(dev_priv)) {
if (crtc_state->base.active || HAS_GMCH(dev_priv)) {
/*
* We start out with underrun reporting disabled to avoid races.
* For correct bookkeeping mark this on active crtcs.
@ -16271,7 +16383,7 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv)
error->pipe[i].source = I915_READ(PIPESRC(i));
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
error->pipe[i].stat = I915_READ(PIPESTAT(i));
}

View File

@ -1061,6 +1061,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
msecs_to_jiffies_timeout(10));
/* just trace the final value */
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
if (!done)
DRM_ERROR("dp aux hw did not signal timeout!\n");
#undef C
@ -1227,6 +1231,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
break;
msleep(1);
}
/* just trace the final value */
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
if (try == 3) {
static u32 last_status = -1;
@ -2141,7 +2147,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
return ret;
}
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
intel_gmch_panel_fitting(intel_crtc, pipe_config,
conn_state->scaling_mode);
else
@ -2152,7 +2158,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
return -EINVAL;
if (HAS_GMCH_DISPLAY(dev_priv) &&
if (HAS_GMCH(dev_priv) &&
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
return -EINVAL;
@ -4608,12 +4614,10 @@ go_again:
return ret;
} else {
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
intel_dp->is_mst = false;
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
/* send a hotplug event */
drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev);
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
intel_dp->is_mst);
}
}
return -EINVAL;
@ -5300,7 +5304,7 @@ bool intel_digital_port_connected(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
if (HAS_GMCH_DISPLAY(dev_priv)) {
if (HAS_GMCH(dev_priv)) {
if (IS_GM45(dev_priv))
return gm45_digital_port_connected(encoder);
else
@ -6038,7 +6042,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
intel_attach_force_audio_property(connector);
intel_attach_broadcast_rgb_property(connector);
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
drm_connector_attach_max_bpc_property(connector, 6, 10);
else if (INTEL_GEN(dev_priv) >= 5)
drm_connector_attach_max_bpc_property(connector, 6, 12);
@ -6047,7 +6051,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
drm_connector_attach_scaling_mode_property(connector, allowed_scalers);
@ -6919,7 +6923,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
@ -7096,7 +7100,10 @@ void intel_dp_mst_resume(struct drm_i915_private *dev_priv)
continue;
ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr);
if (ret)
intel_dp_check_mst_status(intel_dp);
if (ret) {
intel_dp->is_mst = false;
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
false);
}
}
}

View File

@ -213,6 +213,16 @@ struct intel_fbdev {
unsigned long vma_flags;
async_cookie_t cookie;
int preferred_bpp;
/* Whether or not fbdev hpd processing is temporarily suspended */
bool hpd_suspended : 1;
/* Set when a hotplug was received while HPD processing was
* suspended
*/
bool hpd_waiting : 1;
/* Protects hpd_suspended */
struct mutex hpd_lock;
};
struct intel_encoder {
@ -1756,9 +1766,10 @@ static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state);
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 glk_color_ctl(const struct intel_plane_state *plane_state);
u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state);
u32 skl_plane_stride(const struct intel_plane_state *plane_state,
int plane);
int skl_check_plane_surface(struct intel_plane_state *plane_state);
@ -2379,8 +2390,8 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
/* intel_color.c */
void intel_color_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state);
void intel_color_set_csc(struct intel_crtc_state *crtc_state);
void intel_color_load_luts(struct intel_crtc_state *crtc_state);
void intel_color_commit(const struct intel_crtc_state *crtc_state);
void intel_color_load_luts(const struct intel_crtc_state *crtc_state);
/* intel_lspcon.c */
bool lspcon_init(struct intel_digital_port *intel_dig_port);

View File

@ -1086,7 +1086,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine)
* the last request that remains in the timeline. When idle, it is
* the last executed context as tracked by retirement.
*/
rq = __i915_gem_active_peek(&engine->timeline.last_request);
rq = __i915_active_request_peek(&engine->timeline.last_request);
if (rq)
return rq->hw_context == kernel_context;
else

View File

@ -681,6 +681,7 @@ int intel_fbdev_init(struct drm_device *dev)
if (ifbdev == NULL)
return -ENOMEM;
mutex_init(&ifbdev->hpd_lock);
drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);
if (!intel_fbdev_init_bios(dev, ifbdev))
@ -754,6 +755,26 @@ void intel_fbdev_fini(struct drm_i915_private *dev_priv)
intel_fbdev_destroy(ifbdev);
}
/* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD
* processing, fbdev will perform a full connector reprobe if a hotplug event
* was received while HPD was suspended.
*/
static void intel_fbdev_hpd_set_suspend(struct intel_fbdev *ifbdev, int state)
{
bool send_hpd = false;
mutex_lock(&ifbdev->hpd_lock);
ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED;
send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting;
ifbdev->hpd_waiting = false;
mutex_unlock(&ifbdev->hpd_lock);
if (send_hpd) {
DRM_DEBUG_KMS("Handling delayed fbcon HPD event\n");
drm_fb_helper_hotplug_event(&ifbdev->helper);
}
}
void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
{
struct drm_i915_private *dev_priv = to_i915(dev);
@ -775,6 +796,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
*/
if (state != FBINFO_STATE_RUNNING)
flush_work(&dev_priv->fbdev_suspend_work);
console_lock();
} else {
/*
@ -802,17 +824,26 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
drm_fb_helper_set_suspend(&ifbdev->helper, state);
console_unlock();
intel_fbdev_hpd_set_suspend(ifbdev, state);
}
void intel_fbdev_output_poll_changed(struct drm_device *dev)
{
struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
bool send_hpd;
if (!ifbdev)
return;
intel_fbdev_sync(ifbdev);
if (ifbdev->vma || ifbdev->helper.deferred_setup)
mutex_lock(&ifbdev->hpd_lock);
send_hpd = !ifbdev->hpd_suspended;
ifbdev->hpd_waiting = true;
mutex_unlock(&ifbdev->hpd_lock);
if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup))
drm_fb_helper_hotplug_event(&ifbdev->helper);
}

View File

@ -258,7 +258,7 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
old = !crtc->cpu_fifo_underrun_disabled;
crtc->cpu_fifo_underrun_disabled = !enable;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
else if (IS_GEN_RANGE(dev_priv, 5, 6))
ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
@ -369,7 +369,7 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
return;
/* GMCH can't disable fifo underruns, filter them. */
if (HAS_GMCH_DISPLAY(dev_priv) &&
if (HAS_GMCH(dev_priv) &&
crtc->cpu_fifo_underrun_disabled)
return;
@ -421,7 +421,7 @@ void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv)
if (crtc->cpu_fifo_underrun_disabled)
continue;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
i9xx_check_fifo_underruns(crtc);
else if (IS_GEN(dev_priv, 7))
ivybridge_check_fifo_underruns(crtc);

View File

@ -140,6 +140,9 @@ static struct dentry *create_buf_file_callback(const char *filename,
buf_file = debugfs_create_file(filename, mode,
parent, buf, &relay_file_operations);
if (IS_ERR(buf_file))
return NULL;
return buf_file;
}

View File

@ -1588,7 +1588,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
if (hdmi->has_hdmi_sink && !force_dvi) {
/* if we can't do 8bpc we may still be able to do 12bpc */
if (status != MODE_OK && !HAS_GMCH_DISPLAY(dev_priv))
if (status != MODE_OK && !HAS_GMCH(dev_priv))
status = hdmi_port_clock_valid(hdmi, clock * 3 / 2,
true, force_dvi);
@ -1613,7 +1613,7 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
&crtc_state->base.adjusted_mode;
int i;
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
return false;
if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
@ -2150,7 +2150,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
drm_connector_attach_content_type_property(connector);
connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
drm_connector_attach_max_bpc_property(connector, 8, 12);
}

View File

@ -470,7 +470,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
* hotplug bits itself. So only WARN about unexpected
* interrupts on saner platforms.
*/
WARN_ONCE(!HAS_GMCH_DISPLAY(dev_priv),
WARN_ONCE(!HAS_GMCH(dev_priv),
"Received HPD interrupt on pin %d although disabled\n", pin);
continue;
}

View File

@ -823,7 +823,7 @@ int intel_setup_gmbus(struct drm_i915_private *dev_priv)
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
else if (!HAS_GMCH_DISPLAY(dev_priv))
else if (!HAS_GMCH(dev_priv))
/*
* Broxton uses the same PCH offsets for South Display Engine,
* even though it doesn't have a PCH.

View File

@ -1266,8 +1266,6 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma)
return i915_vma_pin(vma, 0, 0, flags);
}
static u32 make_rpcs(struct drm_i915_private *dev_priv);
static void
__execlists_update_reg_state(struct intel_engine_cs *engine,
struct intel_context *ce)
@ -1281,7 +1279,8 @@ __execlists_update_reg_state(struct intel_engine_cs *engine,
/* RPCS */
if (engine->class == RENDER_CLASS)
regs[CTX_R_PWR_CLK_STATE + 1] = make_rpcs(engine->i915);
regs[CTX_R_PWR_CLK_STATE + 1] = gen8_make_rpcs(engine->i915,
&ce->sseu);
}
static struct intel_context *
@ -2431,21 +2430,49 @@ int logical_xcs_ring_init(struct intel_engine_cs *engine)
return logical_ring_init(engine);
}
static u32
make_rpcs(struct drm_i915_private *dev_priv)
u32 gen8_make_rpcs(struct drm_i915_private *i915, struct intel_sseu *req_sseu)
{
bool subslice_pg = RUNTIME_INFO(dev_priv)->sseu.has_subslice_pg;
u8 slices = hweight8(RUNTIME_INFO(dev_priv)->sseu.slice_mask);
u8 subslices = hweight8(RUNTIME_INFO(dev_priv)->sseu.subslice_mask[0]);
const struct sseu_dev_info *sseu = &RUNTIME_INFO(i915)->sseu;
bool subslice_pg = sseu->has_subslice_pg;
struct intel_sseu ctx_sseu;
u8 slices, subslices;
u32 rpcs = 0;
/*
* No explicit RPCS request is needed to ensure full
* slice/subslice/EU enablement prior to Gen9.
*/
if (INTEL_GEN(dev_priv) < 9)
if (INTEL_GEN(i915) < 9)
return 0;
/*
* If i915/perf is active, we want a stable powergating configuration
* on the system.
*
* We could choose full enablement, but on ICL we know there are use
* cases which disable slices for functional, apart for performance
* reasons. So in this case we select a known stable subset.
*/
if (!i915->perf.oa.exclusive_stream) {
ctx_sseu = *req_sseu;
} else {
ctx_sseu = intel_device_default_sseu(i915);
if (IS_GEN(i915, 11)) {
/*
* We only need subslice count so it doesn't matter
* which ones we select - just turn off low bits in the
* amount of half of all available subslices per slice.
*/
ctx_sseu.subslice_mask =
~(~0 << (hweight8(ctx_sseu.subslice_mask) / 2));
ctx_sseu.slice_mask = 0x1;
}
}
slices = hweight8(ctx_sseu.slice_mask);
subslices = hweight8(ctx_sseu.subslice_mask);
/*
* Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits
* wide and Icelake has up to eight subslices, specfial programming is
@ -2471,7 +2498,9 @@ make_rpcs(struct drm_i915_private *dev_priv)
* subslices are enabled, or a count between one and four on the first
* slice.
*/
if (IS_GEN(dev_priv, 11) && slices == 1 && subslices >= 4) {
if (IS_GEN(i915, 11) &&
slices == 1 &&
subslices > min_t(u8, 4, hweight8(sseu->subslice_mask[0]) / 2)) {
GEM_BUG_ON(subslices & 1);
subslice_pg = false;
@ -2484,10 +2513,10 @@ make_rpcs(struct drm_i915_private *dev_priv)
* must make an explicit request through RPCS for full
* enablement.
*/
if (RUNTIME_INFO(dev_priv)->sseu.has_slice_pg) {
if (sseu->has_slice_pg) {
u32 mask, val = slices;
if (INTEL_GEN(dev_priv) >= 11) {
if (INTEL_GEN(i915) >= 11) {
mask = GEN11_RPCS_S_CNT_MASK;
val <<= GEN11_RPCS_S_CNT_SHIFT;
} else {
@ -2512,18 +2541,16 @@ make_rpcs(struct drm_i915_private *dev_priv)
rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;
}
if (RUNTIME_INFO(dev_priv)->sseu.has_eu_pg) {
if (sseu->has_eu_pg) {
u32 val;
val = RUNTIME_INFO(dev_priv)->sseu.eu_per_subslice <<
GEN8_RPCS_EU_MIN_SHIFT;
val = ctx_sseu.min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;
GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);
val &= GEN8_RPCS_EU_MIN_MASK;
rpcs |= val;
val = RUNTIME_INFO(dev_priv)->sseu.eu_per_subslice <<
GEN8_RPCS_EU_MAX_SHIFT;
val = ctx_sseu.max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;
GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);
val &= GEN8_RPCS_EU_MAX_MASK;

View File

@ -112,4 +112,6 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
const char *prefix),
unsigned int max);
u32 gen8_make_rpcs(struct drm_i915_private *i915, struct intel_sseu *ctx_sseu);
#endif /* _INTEL_LRC_H_ */

View File

@ -186,7 +186,7 @@ struct intel_overlay {
struct overlay_registers __iomem *regs;
u32 flip_addr;
/* flip handling */
struct i915_gem_active last_flip;
struct i915_active_request last_flip;
};
static void i830_overlay_clock_gating(struct drm_i915_private *dev_priv,
@ -214,23 +214,23 @@ static void i830_overlay_clock_gating(struct drm_i915_private *dev_priv,
static void intel_overlay_submit_request(struct intel_overlay *overlay,
struct i915_request *rq,
i915_gem_retire_fn retire)
i915_active_retire_fn retire)
{
GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
&overlay->i915->drm.struct_mutex));
i915_gem_active_set_retire_fn(&overlay->last_flip, retire,
&overlay->i915->drm.struct_mutex);
i915_gem_active_set(&overlay->last_flip, rq);
GEM_BUG_ON(i915_active_request_peek(&overlay->last_flip,
&overlay->i915->drm.struct_mutex));
i915_active_request_set_retire_fn(&overlay->last_flip, retire,
&overlay->i915->drm.struct_mutex);
__i915_active_request_set(&overlay->last_flip, rq);
i915_request_add(rq);
}
static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
struct i915_request *rq,
i915_gem_retire_fn retire)
i915_active_retire_fn retire)
{
intel_overlay_submit_request(overlay, rq, retire);
return i915_gem_active_retire(&overlay->last_flip,
&overlay->i915->drm.struct_mutex);
return i915_active_request_retire(&overlay->last_flip,
&overlay->i915->drm.struct_mutex);
}
static struct i915_request *alloc_request(struct intel_overlay *overlay)
@ -351,8 +351,9 @@ static void intel_overlay_release_old_vma(struct intel_overlay *overlay)
i915_vma_put(vma);
}
static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
struct i915_request *rq)
static void
intel_overlay_release_old_vid_tail(struct i915_active_request *active,
struct i915_request *rq)
{
struct intel_overlay *overlay =
container_of(active, typeof(*overlay), last_flip);
@ -360,7 +361,7 @@ static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
intel_overlay_release_old_vma(overlay);
}
static void intel_overlay_off_tail(struct i915_gem_active *active,
static void intel_overlay_off_tail(struct i915_active_request *active,
struct i915_request *rq)
{
struct intel_overlay *overlay =
@ -423,8 +424,8 @@ static int intel_overlay_off(struct intel_overlay *overlay)
* We have to be careful not to repeat work forever an make forward progess. */
static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
{
return i915_gem_active_retire(&overlay->last_flip,
&overlay->i915->drm.struct_mutex);
return i915_active_request_retire(&overlay->last_flip,
&overlay->i915->drm.struct_mutex);
}
/* Wait for pending overlay flip and release old frame.
@ -1357,7 +1358,7 @@ void intel_overlay_setup(struct drm_i915_private *dev_priv)
overlay->contrast = 75;
overlay->saturation = 146;
init_request_active(&overlay->last_flip, NULL);
INIT_ACTIVE_REQUEST(&overlay->last_flip);
mutex_lock(&dev_priv->drm.struct_mutex);

View File

@ -3927,14 +3927,9 @@ static unsigned int skl_cursor_allocation(int num_active)
static void skl_ddb_entry_init_from_hw(struct drm_i915_private *dev_priv,
struct skl_ddb_entry *entry, u32 reg)
{
u16 mask;
if (INTEL_GEN(dev_priv) >= 11)
mask = ICL_DDB_ENTRY_MASK;
else
mask = SKL_DDB_ENTRY_MASK;
entry->start = reg & mask;
entry->end = (reg >> DDB_ENTRY_END_SHIFT) & mask;
entry->start = reg & DDB_ENTRY_MASK;
entry->end = (reg >> DDB_ENTRY_END_SHIFT) & DDB_ENTRY_MASK;
if (entry->end)
entry->end += 1;
@ -4319,7 +4314,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
int num_active;
u64 plane_data_rate[I915_MAX_PLANES] = {};
u64 uv_plane_data_rate[I915_MAX_PLANES] = {};
u16 blocks = 0;
u32 blocks;
int level;
/* Clear the partitioning for disabled planes. */
@ -4694,8 +4689,11 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *cstate,
uint_fixed_16_16_t selected_result;
u32 res_blocks, res_lines, min_ddb_alloc = 0;
if (latency == 0)
if (latency == 0) {
/* reject it */
result->min_ddb_alloc = U16_MAX;
return;
}
/* Display WA #1141: kbl,cfl */
if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) ||
@ -4783,8 +4781,11 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *cstate,
if (!skl_wm_has_lines(dev_priv, level))
res_lines = 0;
if (res_lines > 31)
if (res_lines > 31) {
/* reject it */
result->min_ddb_alloc = U16_MAX;
return;
}
/*
* If res_lines is valid, assume we can use this watermark level

View File

@ -49,19 +49,6 @@ static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine)
I915_GEM_HWS_INDEX_ADDR);
}
static unsigned int __intel_ring_space(unsigned int head,
unsigned int tail,
unsigned int size)
{
/*
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
* same cacheline, the Head Pointer must not be greater than the Tail
* Pointer."
*/
GEM_BUG_ON(!is_power_of_2(size));
return (head - tail - CACHELINE_BYTES) & (size - 1);
}
unsigned int intel_ring_update_space(struct intel_ring *ring)
{
unsigned int space;

View File

@ -403,16 +403,17 @@ struct intel_engine_cs {
/**
* @enable_count: Reference count for the enabled samplers.
*
* Index number corresponds to the bit number from @enable.
* Index number corresponds to @enum drm_i915_pmu_engine_sample.
*/
unsigned int enable_count[I915_PMU_SAMPLE_BITS];
unsigned int enable_count[I915_ENGINE_SAMPLE_COUNT];
/**
* @sample: Counter values for sampling events.
*
* Our internal timer stores the current counters in this field.
*
* Index number corresponds to @enum drm_i915_pmu_engine_sample.
*/
#define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1)
struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX];
struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_COUNT];
} pmu;
/*
@ -592,7 +593,20 @@ intel_engine_has_preemption(const struct intel_engine_cs *engine)
static inline bool __execlists_need_preempt(int prio, int last)
{
return prio > max(0, last);
/*
* Allow preemption of low -> normal -> high, but we do
* not allow low priority tasks to preempt other low priority
* tasks under the impression that latency for low priority
* tasks does not matter (as much as background throughput),
* so kiss.
*
* More naturally we would write
* prio >= max(0, last);
* except that we wish to prevent triggering preemption at the same
* priority level: the task that is running should remain running
* to preserve FIFO ordering of dependencies.
*/
return prio > max(I915_PRIORITY_NORMAL - 1, last);
}
static inline void
@ -818,6 +832,18 @@ intel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
return tail;
}
static inline unsigned int
__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
{
/*
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
* same cacheline, the Head Pointer must not be greater than the Tail
* Pointer."
*/
GEM_BUG_ON(!is_power_of_2(size));
return (head - tail - CACHELINE_BYTES) & (size - 1);
}
void intel_engine_write_global_seqno(struct intel_engine_cs *engine, u32 seqno);
int intel_engine_setup_common(struct intel_engine_cs *engine);

View File

@ -484,9 +484,16 @@ skl_program_plane(struct intel_plane *plane,
struct intel_plane *linked = plane_state->linked_plane;
const struct drm_framebuffer *fb = plane_state->base.fb;
u8 alpha = plane_state->base.alpha >> 8;
u32 plane_color_ctl = 0;
unsigned long irqflags;
u32 keymsk, keymax;
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
plane_color_ctl = plane_state->color_ctl |
glk_plane_color_ctl_crtc(crtc_state);
/* Sizes are 0 based */
src_w--;
src_h--;
@ -533,8 +540,7 @@ skl_program_plane(struct intel_plane *plane,
}
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
plane_state->color_ctl);
I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(plane))
icl_program_input_csc(plane, crtc_state, plane_state);
@ -733,6 +739,11 @@ vlv_update_clrc(const struct intel_plane_state *plane_state)
SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos));
}
static u32 vlv_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
return SP_GAMMA_ENABLE;
}
static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
@ -741,7 +752,7 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 sprctl;
sprctl = SP_ENABLE | SP_GAMMA_ENABLE;
sprctl = SP_ENABLE;
switch (fb->format->format) {
case DRM_FORMAT_YUYV:
@ -808,7 +819,6 @@ vlv_update_plane(struct intel_plane *plane,
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
enum plane_id plane_id = plane->id;
u32 sprctl = plane_state->ctl;
u32 sprsurf_offset = plane_state->color_plane[0].offset;
u32 linear_offset;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
@ -819,6 +829,9 @@ vlv_update_plane(struct intel_plane *plane,
u32 x = plane_state->color_plane[0].x;
u32 y = plane_state->color_plane[0].y;
unsigned long irqflags;
u32 sprctl;
sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state);
/* Sizes are 0 based */
crtc_w--;
@ -901,6 +914,19 @@ vlv_plane_get_hw_state(struct intel_plane *plane,
return ret;
}
static u32 ivb_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
u32 sprctl = 0;
sprctl |= SPRITE_GAMMA_ENABLE;
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
sprctl |= SPRITE_PIPE_CSC_ENABLE;
return sprctl;
}
static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
@ -911,14 +937,11 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 sprctl;
sprctl = SPRITE_ENABLE | SPRITE_GAMMA_ENABLE;
sprctl = SPRITE_ENABLE;
if (IS_IVYBRIDGE(dev_priv))
sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
sprctl |= SPRITE_PIPE_CSC_ENABLE;
switch (fb->format->format) {
case DRM_FORMAT_XBGR8888:
sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
@ -970,7 +993,6 @@ ivb_update_plane(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
u32 sprctl = plane_state->ctl, sprscale = 0;
u32 sprsurf_offset = plane_state->color_plane[0].offset;
u32 linear_offset;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
@ -982,8 +1004,11 @@ ivb_update_plane(struct intel_plane *plane,
u32 y = plane_state->color_plane[0].y;
u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
u32 sprctl, sprscale = 0;
unsigned long irqflags;
sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state);
/* Sizes are 0 based */
src_w--;
src_h--;
@ -1080,6 +1105,11 @@ g4x_sprite_max_stride(struct intel_plane *plane,
return 16384;
}
static u32 g4x_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
{
return DVS_GAMMA_ENABLE;
}
static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
@ -1090,7 +1120,7 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 dvscntr;
dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE;
dvscntr = DVS_ENABLE;
if (IS_GEN(dev_priv, 6))
dvscntr |= DVS_TRICKLE_FEED_DISABLE;
@ -1146,7 +1176,6 @@ g4x_update_plane(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
enum pipe pipe = plane->pipe;
u32 dvscntr = plane_state->ctl, dvsscale = 0;
u32 dvssurf_offset = plane_state->color_plane[0].offset;
u32 linear_offset;
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
@ -1158,8 +1187,11 @@ g4x_update_plane(struct intel_plane *plane,
u32 y = plane_state->color_plane[0].y;
u32 src_w = drm_rect_width(&plane_state->base.src) >> 16;
u32 src_h = drm_rect_height(&plane_state->base.src) >> 16;
u32 dvscntr, dvsscale = 0;
unsigned long irqflags;
dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
/* Sizes are 0 based */
src_w--;
src_h--;

View File

@ -1819,6 +1819,9 @@ int __intel_wait_for_register(struct drm_i915_private *dev_priv,
(reg_value & mask) == value,
slow_timeout_ms * 1000, 10, 1000);
/* just trace the final value */
trace_i915_reg_rw(false, reg, reg_value, sizeof(reg_value), true);
if (out_value)
*out_value = reg_value;

View File

@ -0,0 +1,157 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright © 2018 Intel Corporation
*/
#include "../i915_selftest.h"
#include "igt_flush_test.h"
#include "lib_sw_fence.h"
struct live_active {
struct i915_active base;
bool retired;
};
static void __live_active_retire(struct i915_active *base)
{
struct live_active *active = container_of(base, typeof(*active), base);
active->retired = true;
}
static int __live_active_setup(struct drm_i915_private *i915,
struct live_active *active)
{
struct intel_engine_cs *engine;
struct i915_sw_fence *submit;
enum intel_engine_id id;
unsigned int count = 0;
int err = 0;
submit = heap_fence_create(GFP_KERNEL);
if (!submit)
return -ENOMEM;
i915_active_init(i915, &active->base, __live_active_retire);
active->retired = false;
if (!i915_active_acquire(&active->base)) {
pr_err("First i915_active_acquire should report being idle\n");
err = -EINVAL;
goto out;
}
for_each_engine(engine, i915, id) {
struct i915_request *rq;
rq = i915_request_alloc(engine, i915->kernel_context);
if (IS_ERR(rq)) {
err = PTR_ERR(rq);
break;
}
err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
submit,
GFP_KERNEL);
if (err >= 0)
err = i915_active_ref(&active->base,
rq->fence.context, rq);
i915_request_add(rq);
if (err) {
pr_err("Failed to track active ref!\n");
break;
}
count++;
}
i915_active_release(&active->base);
if (active->retired && count) {
pr_err("i915_active retired before submission!\n");
err = -EINVAL;
}
if (active->base.count != count) {
pr_err("i915_active not tracking all requests, found %d, expected %d\n",
active->base.count, count);
err = -EINVAL;
}
out:
i915_sw_fence_commit(submit);
heap_fence_put(submit);
return err;
}
static int live_active_wait(void *arg)
{
struct drm_i915_private *i915 = arg;
struct live_active active;
intel_wakeref_t wakeref;
int err;
/* Check that we get a callback when requests retire upon waiting */
mutex_lock(&i915->drm.struct_mutex);
wakeref = intel_runtime_pm_get(i915);
err = __live_active_setup(i915, &active);
i915_active_wait(&active.base);
if (!active.retired) {
pr_err("i915_active not retired after waiting!\n");
err = -EINVAL;
}
i915_active_fini(&active.base);
if (igt_flush_test(i915, I915_WAIT_LOCKED))
err = -EIO;
intel_runtime_pm_put(i915, wakeref);
mutex_unlock(&i915->drm.struct_mutex);
return err;
}
static int live_active_retire(void *arg)
{
struct drm_i915_private *i915 = arg;
struct live_active active;
intel_wakeref_t wakeref;
int err;
/* Check that we get a callback when requests are indirectly retired */
mutex_lock(&i915->drm.struct_mutex);
wakeref = intel_runtime_pm_get(i915);
err = __live_active_setup(i915, &active);
/* waits for & retires all requests */
if (igt_flush_test(i915, I915_WAIT_LOCKED))
err = -EIO;
if (!active.retired) {
pr_err("i915_active not retired after flushing!\n");
err = -EINVAL;
}
i915_active_fini(&active.base);
intel_runtime_pm_put(i915, wakeref);
mutex_unlock(&i915->drm.struct_mutex);
return err;
}
int i915_active_live_selftests(struct drm_i915_private *i915)
{
static const struct i915_subtest tests[] = {
SUBTEST(live_active_wait),
SUBTEST(live_active_retire),
};
if (i915_terminally_wedged(&i915->gpu_error))
return 0;
return i915_subtests(tests, i915);
}

View File

@ -24,10 +24,13 @@
#include <linux/prime_numbers.h>
#include "../i915_reset.h"
#include "../i915_selftest.h"
#include "i915_random.h"
#include "igt_flush_test.h"
#include "igt_live_test.h"
#include "igt_reset.h"
#include "igt_spinner.h"
#include "mock_drm.h"
#include "mock_gem_device.h"
@ -576,6 +579,469 @@ out_unlock:
return err;
}
static struct i915_vma *rpcs_query_batch(struct i915_vma *vma)
{
struct drm_i915_gem_object *obj;
u32 *cmd;
int err;
if (INTEL_GEN(vma->vm->i915) < 8)
return ERR_PTR(-EINVAL);
obj = i915_gem_object_create_internal(vma->vm->i915, PAGE_SIZE);
if (IS_ERR(obj))
return ERR_CAST(obj);
cmd = i915_gem_object_pin_map(obj, I915_MAP_WB);
if (IS_ERR(cmd)) {
err = PTR_ERR(cmd);
goto err;
}
*cmd++ = MI_STORE_REGISTER_MEM_GEN8;
*cmd++ = i915_mmio_reg_offset(GEN8_R_PWR_CLK_STATE);
*cmd++ = lower_32_bits(vma->node.start);
*cmd++ = upper_32_bits(vma->node.start);
*cmd = MI_BATCH_BUFFER_END;
i915_gem_object_unpin_map(obj);
err = i915_gem_object_set_to_gtt_domain(obj, false);
if (err)
goto err;
vma = i915_vma_instance(obj, vma->vm, NULL);
if (IS_ERR(vma)) {
err = PTR_ERR(vma);
goto err;
}
err = i915_vma_pin(vma, 0, 0, PIN_USER);
if (err)
goto err;
return vma;
err:
i915_gem_object_put(obj);
return ERR_PTR(err);
}
static int
emit_rpcs_query(struct drm_i915_gem_object *obj,
struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct i915_request **rq_out)
{
struct i915_request *rq;
struct i915_vma *batch;
struct i915_vma *vma;
int err;
GEM_BUG_ON(!intel_engine_can_store_dword(engine));
vma = i915_vma_instance(obj, &ctx->ppgtt->vm, NULL);
if (IS_ERR(vma))
return PTR_ERR(vma);
err = i915_gem_object_set_to_gtt_domain(obj, false);
if (err)
return err;
err = i915_vma_pin(vma, 0, 0, PIN_USER);
if (err)
return err;
batch = rpcs_query_batch(vma);
if (IS_ERR(batch)) {
err = PTR_ERR(batch);
goto err_vma;
}
rq = i915_request_alloc(engine, ctx);
if (IS_ERR(rq)) {
err = PTR_ERR(rq);
goto err_batch;
}
err = engine->emit_bb_start(rq, batch->node.start, batch->node.size, 0);
if (err)
goto err_request;
err = i915_vma_move_to_active(batch, rq, 0);
if (err)
goto skip_request;
err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
if (err)
goto skip_request;
i915_gem_object_set_active_reference(batch->obj);
i915_vma_unpin(batch);
i915_vma_close(batch);
i915_vma_unpin(vma);
*rq_out = i915_request_get(rq);
i915_request_add(rq);
return 0;
skip_request:
i915_request_skip(rq, err);
err_request:
i915_request_add(rq);
err_batch:
i915_vma_unpin(batch);
err_vma:
i915_vma_unpin(vma);
return err;
}
#define TEST_IDLE BIT(0)
#define TEST_BUSY BIT(1)
#define TEST_RESET BIT(2)
static int
__sseu_prepare(struct drm_i915_private *i915,
const char *name,
unsigned int flags,
struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct igt_spinner **spin_out)
{
int ret = 0;
if (flags & (TEST_BUSY | TEST_RESET)) {
struct igt_spinner *spin;
struct i915_request *rq;
spin = kzalloc(sizeof(*spin), GFP_KERNEL);
if (!spin) {
ret = -ENOMEM;
goto out;
}
ret = igt_spinner_init(spin, i915);
if (ret)
return ret;
rq = igt_spinner_create_request(spin, ctx, engine, MI_NOOP);
if (IS_ERR(rq)) {
ret = PTR_ERR(rq);
igt_spinner_fini(spin);
kfree(spin);
goto out;
}
i915_request_add(rq);
if (!igt_wait_for_spinner(spin, rq)) {
pr_err("%s: Spinner failed to start!\n", name);
igt_spinner_end(spin);
igt_spinner_fini(spin);
kfree(spin);
ret = -ETIMEDOUT;
goto out;
}
*spin_out = spin;
}
out:
return ret;
}
static int
__read_slice_count(struct drm_i915_private *i915,
struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct drm_i915_gem_object *obj,
struct igt_spinner *spin,
u32 *rpcs)
{
struct i915_request *rq = NULL;
u32 s_mask, s_shift;
unsigned int cnt;
u32 *buf, val;
long ret;
ret = emit_rpcs_query(obj, ctx, engine, &rq);
if (ret)
return ret;
if (spin)
igt_spinner_end(spin);
ret = i915_request_wait(rq, I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT);
i915_request_put(rq);
if (ret < 0)
return ret;
buf = i915_gem_object_pin_map(obj, I915_MAP_WB);
if (IS_ERR(buf)) {
ret = PTR_ERR(buf);
return ret;
}
if (INTEL_GEN(i915) >= 11) {
s_mask = GEN11_RPCS_S_CNT_MASK;
s_shift = GEN11_RPCS_S_CNT_SHIFT;
} else {
s_mask = GEN8_RPCS_S_CNT_MASK;
s_shift = GEN8_RPCS_S_CNT_SHIFT;
}
val = *buf;
cnt = (val & s_mask) >> s_shift;
*rpcs = val;
i915_gem_object_unpin_map(obj);
return cnt;
}
static int
__check_rpcs(const char *name, u32 rpcs, int slices, unsigned int expected,
const char *prefix, const char *suffix)
{
if (slices == expected)
return 0;
if (slices < 0) {
pr_err("%s: %s read slice count failed with %d%s\n",
name, prefix, slices, suffix);
return slices;
}
pr_err("%s: %s slice count %d is not %u%s\n",
name, prefix, slices, expected, suffix);
pr_info("RPCS=0x%x; %u%sx%u%s\n",
rpcs, slices,
(rpcs & GEN8_RPCS_S_CNT_ENABLE) ? "*" : "",
(rpcs & GEN8_RPCS_SS_CNT_MASK) >> GEN8_RPCS_SS_CNT_SHIFT,
(rpcs & GEN8_RPCS_SS_CNT_ENABLE) ? "*" : "");
return -EINVAL;
}
static int
__sseu_finish(struct drm_i915_private *i915,
const char *name,
unsigned int flags,
struct i915_gem_context *ctx,
struct i915_gem_context *kctx,
struct intel_engine_cs *engine,
struct drm_i915_gem_object *obj,
unsigned int expected,
struct igt_spinner *spin)
{
unsigned int slices =
hweight32(intel_device_default_sseu(i915).slice_mask);
u32 rpcs = 0;
int ret = 0;
if (flags & TEST_RESET) {
ret = i915_reset_engine(engine, "sseu");
if (ret)
goto out;
}
ret = __read_slice_count(i915, ctx, engine, obj,
flags & TEST_RESET ? NULL : spin, &rpcs);
ret = __check_rpcs(name, rpcs, ret, expected, "Context", "!");
if (ret)
goto out;
ret = __read_slice_count(i915, kctx, engine, obj, NULL, &rpcs);
ret = __check_rpcs(name, rpcs, ret, slices, "Kernel context", "!");
out:
if (spin)
igt_spinner_end(spin);
if ((flags & TEST_IDLE) && ret == 0) {
ret = i915_gem_wait_for_idle(i915,
I915_WAIT_LOCKED,
MAX_SCHEDULE_TIMEOUT);
if (ret)
return ret;
ret = __read_slice_count(i915, ctx, engine, obj, NULL, &rpcs);
ret = __check_rpcs(name, rpcs, ret, expected,
"Context", " after idle!");
}
return ret;
}
static int
__sseu_test(struct drm_i915_private *i915,
const char *name,
unsigned int flags,
struct i915_gem_context *ctx,
struct intel_engine_cs *engine,
struct drm_i915_gem_object *obj,
struct intel_sseu sseu)
{
struct igt_spinner *spin = NULL;
struct i915_gem_context *kctx;
int ret;
kctx = kernel_context(i915);
if (IS_ERR(kctx))
return PTR_ERR(kctx);
ret = __sseu_prepare(i915, name, flags, ctx, engine, &spin);
if (ret)
goto out;
ret = __i915_gem_context_reconfigure_sseu(ctx, engine, sseu);
if (ret)
goto out;
ret = __sseu_finish(i915, name, flags, ctx, kctx, engine, obj,
hweight32(sseu.slice_mask), spin);
out:
if (spin) {
igt_spinner_end(spin);
igt_spinner_fini(spin);
kfree(spin);
}
kernel_context_close(kctx);
return ret;
}
static int
__igt_ctx_sseu(struct drm_i915_private *i915,
const char *name,
unsigned int flags)
{
struct intel_sseu default_sseu = intel_device_default_sseu(i915);
struct intel_engine_cs *engine = i915->engine[RCS];
struct drm_i915_gem_object *obj;
struct i915_gem_context *ctx;
struct intel_sseu pg_sseu;
intel_wakeref_t wakeref;
struct drm_file *file;
int ret;
if (INTEL_GEN(i915) < 9)
return 0;
if (!RUNTIME_INFO(i915)->sseu.has_slice_pg)
return 0;
if (hweight32(default_sseu.slice_mask) < 2)
return 0;
/*
* Gen11 VME friendly power-gated configuration with half enabled
* sub-slices.
*/
pg_sseu = default_sseu;
pg_sseu.slice_mask = 1;
pg_sseu.subslice_mask =
~(~0 << (hweight32(default_sseu.subslice_mask) / 2));
pr_info("SSEU subtest '%s', flags=%x, def_slices=%u, pg_slices=%u\n",
name, flags, hweight32(default_sseu.slice_mask),
hweight32(pg_sseu.slice_mask));
file = mock_file(i915);
if (IS_ERR(file))
return PTR_ERR(file);
if (flags & TEST_RESET)
igt_global_reset_lock(i915);
mutex_lock(&i915->drm.struct_mutex);
ctx = i915_gem_create_context(i915, file->driver_priv);
if (IS_ERR(ctx)) {
ret = PTR_ERR(ctx);
goto out_unlock;
}
obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
if (IS_ERR(obj)) {
ret = PTR_ERR(obj);
goto out_unlock;
}
wakeref = intel_runtime_pm_get(i915);
/* First set the default mask. */
ret = __sseu_test(i915, name, flags, ctx, engine, obj, default_sseu);
if (ret)
goto out_fail;
/* Then set a power-gated configuration. */
ret = __sseu_test(i915, name, flags, ctx, engine, obj, pg_sseu);
if (ret)
goto out_fail;
/* Back to defaults. */
ret = __sseu_test(i915, name, flags, ctx, engine, obj, default_sseu);
if (ret)
goto out_fail;
/* One last power-gated configuration for the road. */
ret = __sseu_test(i915, name, flags, ctx, engine, obj, pg_sseu);
if (ret)
goto out_fail;
out_fail:
if (igt_flush_test(i915, I915_WAIT_LOCKED))
ret = -EIO;
i915_gem_object_put(obj);
intel_runtime_pm_put(i915, wakeref);
out_unlock:
mutex_unlock(&i915->drm.struct_mutex);
if (flags & TEST_RESET)
igt_global_reset_unlock(i915);
mock_file_free(i915, file);
if (ret)
pr_err("%s: Failed with %d!\n", name, ret);
return ret;
}
static int igt_ctx_sseu(void *arg)
{
struct {
const char *name;
unsigned int flags;
} *phase, phases[] = {
{ .name = "basic", .flags = 0 },
{ .name = "idle", .flags = TEST_IDLE },
{ .name = "busy", .flags = TEST_BUSY },
{ .name = "busy-reset", .flags = TEST_BUSY | TEST_RESET },
{ .name = "busy-idle", .flags = TEST_BUSY | TEST_IDLE },
{ .name = "reset-idle", .flags = TEST_RESET | TEST_IDLE },
};
unsigned int i;
int ret = 0;
for (i = 0, phase = phases; ret == 0 && i < ARRAY_SIZE(phases);
i++, phase++)
ret = __igt_ctx_sseu(arg, phase->name, phase->flags);
return ret;
}
static int igt_ctx_readonly(void *arg)
{
struct drm_i915_private *i915 = arg;
@ -1162,6 +1628,7 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv)
SUBTEST(live_nop_switch),
SUBTEST(igt_ctx_exec),
SUBTEST(igt_ctx_readonly),
SUBTEST(igt_ctx_sseu),
SUBTEST(igt_vm_isolation),
};

View File

@ -12,8 +12,9 @@
selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
selftest(uncore, intel_uncore_live_selftests)
selftest(workarounds, intel_workarounds_live_selftests)
selftest(requests, i915_request_live_selftests)
selftest(timelines, i915_timeline_live_selftests)
selftest(requests, i915_request_live_selftests)
selftest(active, i915_active_live_selftests)
selftest(objects, i915_gem_object_live_selftests)
selftest(dmabuf, i915_gem_dmabuf_live_selftests)
selftest(coherency, i915_gem_coherency_live_selftests)

View File

@ -4,6 +4,8 @@
* Copyright © 2018 Intel Corporation
*/
#include <linux/prime_numbers.h>
#include "../i915_reset.h"
#include "../i915_selftest.h"
@ -405,6 +407,106 @@ err_wedged:
goto err_client_b;
}
static int live_chain_preempt(void *arg)
{
struct drm_i915_private *i915 = arg;
struct intel_engine_cs *engine;
struct preempt_client hi, lo;
enum intel_engine_id id;
intel_wakeref_t wakeref;
int err = -ENOMEM;
/*
* Build a chain AB...BA between two contexts (A, B) and request
* preemption of the last request. It should then complete before
* the previously submitted spinner in B.
*/
if (!HAS_LOGICAL_RING_PREEMPTION(i915))
return 0;
mutex_lock(&i915->drm.struct_mutex);
wakeref = intel_runtime_pm_get(i915);
if (preempt_client_init(i915, &hi))
goto err_unlock;
if (preempt_client_init(i915, &lo))
goto err_client_hi;
for_each_engine(engine, i915, id) {
struct i915_sched_attr attr = {
.priority = I915_USER_PRIORITY(I915_PRIORITY_MAX),
};
int count, i;
for_each_prime_number_from(count, 1, 32) { /* must fit ring! */
struct i915_request *rq;
rq = igt_spinner_create_request(&hi.spin,
hi.ctx, engine,
MI_ARB_CHECK);
if (IS_ERR(rq))
goto err_wedged;
i915_request_add(rq);
if (!igt_wait_for_spinner(&hi.spin, rq))
goto err_wedged;
rq = igt_spinner_create_request(&lo.spin,
lo.ctx, engine,
MI_ARB_CHECK);
if (IS_ERR(rq))
goto err_wedged;
i915_request_add(rq);
for (i = 0; i < count; i++) {
rq = i915_request_alloc(engine, lo.ctx);
if (IS_ERR(rq))
goto err_wedged;
i915_request_add(rq);
}
rq = i915_request_alloc(engine, hi.ctx);
if (IS_ERR(rq))
goto err_wedged;
i915_request_add(rq);
engine->schedule(rq, &attr);
igt_spinner_end(&hi.spin);
if (i915_request_wait(rq, I915_WAIT_LOCKED, HZ / 5) < 0) {
struct drm_printer p =
drm_info_printer(i915->drm.dev);
pr_err("Failed to preempt over chain of %d\n",
count);
intel_engine_dump(engine, &p,
"%s\n", engine->name);
goto err_wedged;
}
igt_spinner_end(&lo.spin);
}
}
err = 0;
err_client_lo:
preempt_client_fini(&lo);
err_client_hi:
preempt_client_fini(&hi);
err_unlock:
if (igt_flush_test(i915, I915_WAIT_LOCKED))
err = -EIO;
intel_runtime_pm_put(i915, wakeref);
mutex_unlock(&i915->drm.struct_mutex);
return err;
err_wedged:
igt_spinner_end(&hi.spin);
igt_spinner_end(&lo.spin);
i915_gem_set_wedged(i915);
err = -EIO;
goto err_client_lo;
}
static int live_preempt_hang(void *arg)
{
struct drm_i915_private *i915 = arg;
@ -785,6 +887,7 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
SUBTEST(live_preempt),
SUBTEST(live_late_preempt),
SUBTEST(live_suppress_self_preempt),
SUBTEST(live_chain_preempt),
SUBTEST(live_preempt_hang),
SUBTEST(live_preempt_smoke),
};

View File

@ -15,7 +15,8 @@ void mock_timeline_init(struct i915_timeline *timeline, u64 context)
spin_lock_init(&timeline->lock);
init_request_active(&timeline->last_request, NULL);
INIT_ACTIVE_REQUEST(&timeline->barrier);
INIT_ACTIVE_REQUEST(&timeline->last_request);
INIT_LIST_HEAD(&timeline->requests);
i915_syncmap_init(&timeline->sync);

View File

@ -275,7 +275,7 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder,
if (fixed_mode) {
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
if (HAS_GMCH_DISPLAY(dev_priv))
if (HAS_GMCH(dev_priv))
intel_gmch_panel_fitting(crtc, pipe_config,
conn_state->scaling_mode);
else
@ -1633,7 +1633,7 @@ static void intel_dsi_add_properties(struct intel_connector *connector)
u32 allowed_scalers;
allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
if (!HAS_GMCH_DISPLAY(dev_priv))
if (!HAS_GMCH(dev_priv))
allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
drm_connector_attach_scaling_mode_property(&connector->base,

View File

@ -1486,9 +1486,73 @@ struct drm_i915_gem_context_param {
#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */
#define I915_CONTEXT_DEFAULT_PRIORITY 0
#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */
/*
* When using the following param, value should be a pointer to
* drm_i915_gem_context_param_sseu.
*/
#define I915_CONTEXT_PARAM_SSEU 0x7
__u64 value;
};
/**
* Context SSEU programming
*
* It may be necessary for either functional or performance reason to configure
* a context to run with a reduced number of SSEU (where SSEU stands for Slice/
* Sub-slice/EU).
*
* This is done by configuring SSEU configuration using the below
* @struct drm_i915_gem_context_param_sseu for every supported engine which
* userspace intends to use.
*
* Not all GPUs or engines support this functionality in which case an error
* code -ENODEV will be returned.
*
* Also, flexibility of possible SSEU configuration permutations varies between
* GPU generations and software imposed limitations. Requesting such a
* combination will return an error code of -EINVAL.
*
* NOTE: When perf/OA is active the context's SSEU configuration is ignored in
* favour of a single global setting.
*/
struct drm_i915_gem_context_param_sseu {
/*
* Engine class & instance to be configured or queried.
*/
__u16 engine_class;
__u16 engine_instance;
/*
* Unused for now. Must be cleared to zero.
*/
__u32 flags;
/*
* Mask of slices to enable for the context. Valid values are a subset
* of the bitmask value returned for I915_PARAM_SLICE_MASK.
*/
__u64 slice_mask;
/*
* Mask of subslices to enable for the context. Valid values are a
* subset of the bitmask value return by I915_PARAM_SUBSLICE_MASK.
*/
__u64 subslice_mask;
/*
* Minimum/Maximum number of EUs to enable per subslice for the
* context. min_eus_per_subslice must be inferior or equal to
* max_eus_per_subslice.
*/
__u16 min_eus_per_subslice;
__u16 max_eus_per_subslice;
/*
* Unused for now. Must be cleared to zero.
*/
__u32 rsvd;
};
enum drm_i915_oa_format {
I915_OA_FORMAT_A13 = 1, /* HSW only */
I915_OA_FORMAT_A29, /* HSW only */