Re: [Intel-gfx] [PATCH 1/3] drm: Export routines for inserting preallocated nodes into the mm manager
On Fri, 07 Dec 2012, Chris Wilson wrote: > Required by i915 in order to avoid the allocation in the middle of > manipulating the drm_mm lists. > > Use a pair of stubs to preserve the existing EXPORT_SYMBOLs for > backporting; to be removed later. Regardless of whether you choose to do anything about the two nitpicks below or not, Reviewed-by: Jani Nikula > > Cc: Dave Airlie > Cc: dri-de...@lists.freedesktop.org > Signed-off-by: Chris Wilson > --- > drivers/gpu/drm/drm_mm.c | 42 ++ > include/drm/drm_mm.h | 27 +++ > 2 files changed, 53 insertions(+), 16 deletions(-) > > diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c > index 0761a03..d93dc05 100644 > --- a/drivers/gpu/drm/drm_mm.c > +++ b/drivers/gpu/drm/drm_mm.c > @@ -184,19 +184,27 @@ EXPORT_SYMBOL(drm_mm_get_block_generic); > * -ENOSPC if no suitable free area is available. The preallocated memory > node > * must be cleared. > */ > -int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, > -unsigned long size, unsigned alignment) > +int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, > +unsigned long size, unsigned alignment, > +unsigned long color, int atomic) > { > struct drm_mm_node *hole_node; > > - hole_node = drm_mm_search_free(mm, size, alignment, false); > + hole_node = drm_mm_search_free_generic(mm, size, alignment, > +color, atomic); The last param for drm_mm_search_free_generic is a bool, any reason not to make atomic a bool too? > if (!hole_node) > return -ENOSPC; > > - drm_mm_insert_helper(hole_node, node, size, alignment, 0); > - > + drm_mm_insert_helper(hole_node, node, size, alignment, color); > return 0; > } > +EXPORT_SYMBOL(drm_mm_insert_node_generic); > + > +int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, > +unsigned long size, unsigned alignment) > +{ > + return drm_mm_insert_node_generic(mm, node, size, alignment, 0, false); > +} > EXPORT_SYMBOL(drm_mm_insert_node); > > static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, > @@ -275,22 +283,32 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic); > * -ENOSPC if no suitable free area is available. This is for range > * restricted allocations. The preallocated memory node must be cleared. > */ > -int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, > - unsigned long size, unsigned alignment, > - unsigned long start, unsigned long end) > +int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct > drm_mm_node *node, > + unsigned long size, unsigned alignment, > unsigned long color, > + unsigned long start, unsigned long end, > + int atomic) > { > struct drm_mm_node *hole_node; > > - hole_node = drm_mm_search_free_in_range(mm, size, alignment, > - start, end, false); > + hole_node = drm_mm_search_free_in_range_generic(mm, > + size, alignment, color, > + start, end, atomic); Same as above. > if (!hole_node) > return -ENOSPC; > > - drm_mm_insert_helper_range(hole_node, node, size, alignment, 0, > + drm_mm_insert_helper_range(hole_node, node, > +size, alignment, color, > start, end); > - > return 0; > } > +EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); > + > +int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, > + unsigned long size, unsigned alignment, > + unsigned long start, unsigned long end) > +{ > + return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, > 0, start, end, false); > +} > EXPORT_SYMBOL(drm_mm_insert_node_in_range); > > /** > diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h > index 06d7f79..87b0968 100644 > --- a/include/drm/drm_mm.h > +++ b/include/drm/drm_mm.h > @@ -158,12 +158,31 @@ static inline struct drm_mm_node > *drm_mm_get_block_atomic_range( > return drm_mm_get_block_range_generic(parent, size, alignment, 0, > start, end, 1); > } > -extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, > - unsigned long size, unsigned alignment); > + > +extern int drm_mm_insert_node(struct drm_mm *mm, > + struct drm_mm_node *node, > + unsigned long size, > +
Re: [Intel-gfx] [PATCH 2/3] drm/i915: Preallocate the drm_mm_node prior to manipulating the GTT drm_mm manager
On Fri, 07 Dec 2012, Chris Wilson wrote: > As we may reap neighbouring objects in order to free up pages for > allocations, we need to be careful not to allocate in the middle of the > drm_mm manager. To accomplish this, we can simply allocate the > drm_mm_node up front and then use the combined search & insert > drm_mm routines, reducing our code footprint in the process. > > Fixes (partially) i-g-t/gem_tiled_swapping > > Reported-by: Mika Kuoppala > Signed-off-by: Chris Wilson > --- > drivers/gpu/drm/i915/i915_gem.c | 64 > +-- > 1 file changed, 27 insertions(+), 37 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c > index c1f6919..d17f52d 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -2890,7 +2890,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object > *obj, > { > struct drm_device *dev = obj->base.dev; > drm_i915_private_t *dev_priv = dev->dev_private; > - struct drm_mm_node *free_space; > + struct drm_mm_node *node; > u32 size, fence_size, fence_alignment, unfenced_alignment; > bool mappable, fenceable; > int ret; > @@ -2936,66 +2936,56 @@ i915_gem_object_bind_to_gtt(struct > drm_i915_gem_object *obj, > > i915_gem_object_pin_pages(obj); > > + node = kzalloc(sizeof(*node), GFP_KERNEL); > + if (node == NULL) { > + i915_gem_object_unpin_pages(obj); > + return -ENOMEM; > + } Any reason not to do the kzalloc before i915_gem_object_pin_pages, with a slight simplification of the error path there? Otherwise, with the disclaimer that I'm a newbie in drm mm, Reviewed-by: Jani Nikula > + > search_free: > if (map_and_fenceable) > - free_space = > drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, > -size, alignment, > obj->cache_level, > -0, > dev_priv->mm.gtt_mappable_end, > -false); > + ret = > drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, > + size, alignment, > obj->cache_level, > + 0, > dev_priv->mm.gtt_mappable_end, > + false); > else > - free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space, > - size, alignment, > obj->cache_level, > - false); > - > - if (free_space != NULL) { > - if (map_and_fenceable) > - free_space = > - drm_mm_get_block_range_generic(free_space, > -size, alignment, > obj->cache_level, > -0, > dev_priv->mm.gtt_mappable_end, > -false); > - else > - free_space = > - drm_mm_get_block_generic(free_space, > - size, alignment, > obj->cache_level, > - false); > - } > - if (free_space == NULL) { > + ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, > + size, alignment, > obj->cache_level, > + false); > + if (ret) { > ret = i915_gem_evict_something(dev, size, alignment, > obj->cache_level, > map_and_fenceable, > nonblocking); > - if (ret) { > - i915_gem_object_unpin_pages(obj); > - return ret; > - } > + if (ret == 0) > + goto search_free; > > - goto search_free; > + i915_gem_object_unpin_pages(obj); > + kfree(node); > + return ret; > } > - if (WARN_ON(!i915_gem_valid_gtt_space(dev, > - free_space, > - obj->cache_level))) { > + if (WARN_ON(!i915_gem_valid_gtt_space(dev, node, obj->cache_level))) { > i915_gem_object_unpin_pages(obj); > - drm_mm_put_block(free_space); > + drm_mm_put_block(node); > return -EINVAL; > } > > ret = i915_gem_gtt_prepare_object(obj); > if (ret) { > i915_gem_object_unpin_pages(obj); > - drm_mm_put_block(fr
Re: [Intel-gfx] [PATCH 2/3] drm/i915: Preallocate the drm_mm_node prior to manipulating the GTT drm_mm manager
On Wed, 12 Dec 2012 12:18:35 +0200, Jani Nikula wrote: > On Fri, 07 Dec 2012, Chris Wilson wrote: > > As we may reap neighbouring objects in order to free up pages for > > allocations, we need to be careful not to allocate in the middle of the > > drm_mm manager. To accomplish this, we can simply allocate the > > drm_mm_node up front and then use the combined search & insert > > drm_mm routines, reducing our code footprint in the process. > > > > Fixes (partially) i-g-t/gem_tiled_swapping > > > > Reported-by: Mika Kuoppala > > Signed-off-by: Chris Wilson > > --- > > drivers/gpu/drm/i915/i915_gem.c | 64 > > +-- > > 1 file changed, 27 insertions(+), 37 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_gem.c > > b/drivers/gpu/drm/i915/i915_gem.c > > index c1f6919..d17f52d 100644 > > --- a/drivers/gpu/drm/i915/i915_gem.c > > +++ b/drivers/gpu/drm/i915/i915_gem.c > > @@ -2890,7 +2890,7 @@ i915_gem_object_bind_to_gtt(struct > > drm_i915_gem_object *obj, > > { > > struct drm_device *dev = obj->base.dev; > > drm_i915_private_t *dev_priv = dev->dev_private; > > - struct drm_mm_node *free_space; > > + struct drm_mm_node *node; > > u32 size, fence_size, fence_alignment, unfenced_alignment; > > bool mappable, fenceable; > > int ret; > > @@ -2936,66 +2936,56 @@ i915_gem_object_bind_to_gtt(struct > > drm_i915_gem_object *obj, > > > > i915_gem_object_pin_pages(obj); > > > > + node = kzalloc(sizeof(*node), GFP_KERNEL); > > + if (node == NULL) { > > + i915_gem_object_unpin_pages(obj); > > + return -ENOMEM; > > + } > > Any reason not to do the kzalloc before i915_gem_object_pin_pages, with > a slight simplification of the error path there? No reason at all. In my defense, I was trying to make the code as similar as possible... -Chris -- Chris Wilson, Intel Open Source Technology Centre ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 3/3] drm/i915: Preallocate mm node for GTT mmap offset
On Fri, 07 Dec 2012, Chris Wilson wrote: > As the shrinker may be invoked for the allocation, and it may reap > neighbouring objects in the offset range mm, we need to be careful in > the order in which we allocate the node, search for free space and then > insert the node into the mmap offset range manager. > > Fixes i-g-t/gem_tiled_swapping > > Reported-by: Mika Kuoppala > Signed-off-by: Chris Wilson > --- > drivers/gpu/drm/i915/i915_gem.c | 59 > --- > 1 file changed, 49 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c > index d17f52d..3ab97c6 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -1512,14 +1512,29 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device > *dev, > static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object > *obj) > { > struct drm_i915_private *dev_priv = obj->base.dev->dev_private; > + struct drm_gem_mm *mm = obj->base.dev->mm_private; > + struct drm_map_list *list; > int ret; > > - if (obj->base.map_list.map) > + list = &obj->base.map_list; > + if (list->map) > return 0; > > - ret = drm_gem_create_mmap_offset(&obj->base); > - if (ret != -ENOSPC) > - return ret; > + /* Set the object up for mmap'ing */ > + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); sizeof(struct drm_local_map) or sizeof(*list->map) instead? Hmm, it's like this in drm_gem_create_mmap_offset too, either it's a bug or I'm being clueless. Other than that, with the same disclaimer as on the previous patch, Reviewed-by: Jani Nikula > + if (!list->map) > + return -ENOMEM; > + > + list->map->type = _DRM_GEM; > + list->map->size = obj->base.size; > + list->map->handle = &obj->base; > + > + /* Get a DRM GEM mmap offset allocated... */ > + list->file_offset_node = kzalloc(sizeof(struct drm_mm_node), > GFP_KERNEL); > + if (list->file_offset_node == NULL) { > + ret = -ENOMEM; > + goto out_free_list; > + } > > /* Badly fragmented mmap space? The only way we can recover >* space is by destroying unwanted objects. We can't randomly release > @@ -1528,13 +1543,37 @@ static int i915_gem_object_create_mmap_offset(struct > drm_i915_gem_object *obj) >* offsets on purgeable objects by truncating it and marking it purged, >* which prevents userspace from ever using that object again. >*/ > - i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT); > - ret = drm_gem_create_mmap_offset(&obj->base); > - if (ret != -ENOSPC) > - return ret; > + ret = drm_mm_insert_node(&mm->offset_manager, list->file_offset_node, > + obj->base.size / PAGE_SIZE, 0); > + if (ret) { > + i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT); > + ret = drm_mm_insert_node(&mm->offset_manager, > list->file_offset_node, > + obj->base.size / PAGE_SIZE, 0); > + } > + if (ret) { > + i915_gem_shrink_all(dev_priv); > + ret = drm_mm_insert_node(&mm->offset_manager, > list->file_offset_node, > + obj->base.size / PAGE_SIZE, 0); > + } > + if (ret) { > + kfree(list->file_offset_node); > + goto out_free_list; > + } > + > + list->hash.key = list->file_offset_node->start; > + ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); > + if (ret) > + goto out_free_mm; > > - i915_gem_shrink_all(dev_priv); > - return drm_gem_create_mmap_offset(&obj->base); > + return 0; > + > +out_free_mm: > + drm_mm_put_block(list->file_offset_node); > +out_free_list: > + kfree(list->map); > + list->map = NULL; > + > + return ret; > } > > static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) > -- > 1.7.10.4 > > ___ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 3/3] drm/i915: Preallocate mm node for GTT mmap offset
On Wed, 12 Dec 2012 12:48:43 +0200, Jani Nikula wrote: > On Fri, 07 Dec 2012, Chris Wilson wrote: > > As the shrinker may be invoked for the allocation, and it may reap > > neighbouring objects in the offset range mm, we need to be careful in > > the order in which we allocate the node, search for free space and then > > insert the node into the mmap offset range manager. > > > > Fixes i-g-t/gem_tiled_swapping > > > > Reported-by: Mika Kuoppala > > Signed-off-by: Chris Wilson > > --- > > drivers/gpu/drm/i915/i915_gem.c | 59 > > --- > > 1 file changed, 49 insertions(+), 10 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_gem.c > > b/drivers/gpu/drm/i915/i915_gem.c > > index d17f52d..3ab97c6 100644 > > --- a/drivers/gpu/drm/i915/i915_gem.c > > +++ b/drivers/gpu/drm/i915/i915_gem.c > > @@ -1512,14 +1512,29 @@ i915_gem_get_unfenced_gtt_alignment(struct > > drm_device *dev, > > static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object > > *obj) > > { > > struct drm_i915_private *dev_priv = obj->base.dev->dev_private; > > + struct drm_gem_mm *mm = obj->base.dev->mm_private; > > + struct drm_map_list *list; > > int ret; > > > > - if (obj->base.map_list.map) > > + list = &obj->base.map_list; > > + if (list->map) > > return 0; > > > > - ret = drm_gem_create_mmap_offset(&obj->base); > > - if (ret != -ENOSPC) > > - return ret; > > + /* Set the object up for mmap'ing */ > > + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); > > sizeof(struct drm_local_map) or sizeof(*list->map) instead? > > Hmm, it's like this in drm_gem_create_mmap_offset too, either it's a bug > or I'm being clueless. You're right it's a a bug but fortunately in the safe direction, I'd vote for sizeof(*list->map) as unequivocal. -Chris -- Chris Wilson, Intel Open Source Technology Centre ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 00/37] [RFC] revamped modeset locking
Hi all, First thing first: It works, I now no longer have a few dropped frames every 10s on my testbox here with the pageflip i-g-t tests. Random notes: - New design has per-crtc locks to protect the crtc input-side (pageflip, cursor) for r/w and the output state of the crtc (mode, dpms) as read-only. It also required completely revamped fb lifecycle management, those are now refcounted for real (which is a nice cleanup). Imo the proposed rwsem hack from Dave/Ajax is too ugly to life in comparison. - Smoke tested on i915, compile tested for x86 drivers, probably all arm drivers trivially broken. I plan add tons of i-g-t testscases to exercise all the cornercases with i915 (so that lockdep has full coverage among other things) and at least run radeon/nouveau a bit. I also need to set up an arm crosscompiler. Generally testing feedback on !i915 highly welcome. - Driver audit: I've tried to not break anything more than it already is, and for the big three desktop drivers fixup any related breakage I've noticed. Big unknown is vmwgfx since that driver is over my head. Generally review from driver devs is required to check all corner-cases. - Merging, presuming people like this idea here: I think it'd be good to slurp in the driver changes as early as possible. The big rework probably has to go in with a separate pull directly to drm-next for all drivers - there are simply too many sync-points in this rework where all drivers need to follow the new rules before core drm changes can be applied. - Having a global lock which synchronizing object destruction is a royal pain, since it reliably results in that locking getting in the way almost everywhere when trying to implement refcounting. It's fixed now for fb & the mode_config mutex, but I'm already eagerly looking forward to simplifying dev->struct_mutex gem_bo cleanup rules. - drm teardown/setup synchronization and locking is terminally broken. Insane volunteers welcome, I don't want to do this. - I've mentioned that reading too much driver code causes nightmares, right? vmwgfx ... Please bring on the flames. Cheers, Daniel Daniel Vetter (37): drm: review locking rules in drm_crtc.c drm/doc: integrate drm_crtc.c kerneldoc drm: add drm_modeset_lock|unlock_all drm/i915: rework locking for intel_dpio|sbi_read|write drm/i915: use drm_modeset_lock_all drm/gma500: use drm_modeset_lock_all drm/ast: use drm_modeset_lock_all drm/shmobile: use drm_modeset_lock_all drm/vmgfx: use drm_modeset_lock_all drm: add per-crtc locks drm/radeon: add W|RREG32_IDX for MM_INDEX|DATA based mmio accesss drm/radeon: make indirect register access concurrency-safe drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex drm: only take the crtc lock for ->cursor_set drm: only take the crtc lock for ->cursor_move drm/: reorder framebuffer init sequence drm: revamp locking around fb creation/destruction drm: create drm_framebuffer_lookup drm/gma500: move fbcon restore to lastclose drm: revamp framebuffer cleanup interfaces drm: reference framebuffers which are on the idr drm: nest modeset locks within fpriv->fbs_lock drm/i915: fixup overlay stolen memory leak drm: push modeset_lock_all into ->fb_create driver callbacks drm: don't take modeset locks in getfb ioctl drm: fb refcounting for dirtyfb_ioctl drm: refcounting for sprite framebuffers drm: encapsulate crtc->set_config calls drm: refcounting for crtc framebuffers drm/i915: dump refcount into framebuffer debugfs file drm/vmwgfx: add proper framebuffer refcounting drm: optimize drm_framebuffer_remove drm/nouveau: try to protect nbo->pin_refcount drm/ttm: fix fence locking in ttm_buffer_object_transfer drm/radeon: fix fence locking in the pageflip callback drm: only grab the crtc lock for pageflips drm: don't hold crtc mutexes for connector ->detect callbacks Documentation/DocBook/drm.tmpl|4 + drivers/gpu/drm/ast/ast_drv.c |4 +- drivers/gpu/drm/ast/ast_drv.h |2 + drivers/gpu/drm/ast/ast_fb.c |1 + drivers/gpu/drm/ast/ast_main.c|6 +- drivers/gpu/drm/cirrus/cirrus_fbdev.c |1 + drivers/gpu/drm/cirrus/cirrus_main.c | 11 +- drivers/gpu/drm/drm_crtc.c| 782 + drivers/gpu/drm/drm_fb_cma_helper.c | 15 +- drivers/gpu/drm/drm_fb_helper.c | 26 +- drivers/gpu/drm/drm_fops.c|1 + drivers/gpu/drm/exynos/exynos_drm_fb.c| 20 +- drivers/gpu/drm/exynos/exynos_drm_fbdev.c |4 +- drivers/gpu/drm/gma500/framebuffer.c | 29 +- drivers/gpu/drm/gma500/psb_drv.c | 15 +- drivers/gpu/drm/i2c/ch7006_drv.c |2 +- drivers/gpu/drm/i915/i915_debugfs.c | 19 +- drivers/gpu/drm/i915/i915_dma.c |4 +- drivers/gpu/drm/i915/i915_drv.h |2 +- drivers/gpu/drm/i915/intel_disp
[Intel-gfx] [PATCH 01/37] drm: review locking rules in drm_crtc.c
- config_cleanup was confused: It claimed that callers need to hold the modeset lock, but the connector|encoder_cleanup helpers grabbed that themselves (note that crtc_cleanup did _not_ grab the modeset lock). Which resulted in all drivers _not_ hodling the lock. Since this is for single-threaded cleanup code, drop the requirement from docs and also drop the lock_grabbing from all _cleanup functions. - Kill the LOCKING section in the doctype, since clearly we're not good enough to keep them up-to-date. And misleading locking documentation is worse than useless (see e.g. the comment in the vmgfx driver about the cleanup mess). And since for most functions the very first line either grabs the lock or has a WARN_ON(!locked) the documentation doesn't really add anything. - Instead put in some effort into explaining the only two special cases a bit better: config_init and config_cleanup are both called from single-threaded setup/teardown code, so don't do any locking. It's the driver's job though to enforce this. - Where lacking, add a WARN_ON(!is_locked). Not many places though, since locking around fbdev setup/teardown is through-roughly screwed up, and so will break almost every single WARN annotation I've tried to add. - Add a drm_modeset_is_locked helper - the Grate Modset Locking Rework will use the compiler to assist in the big reorg by renaming the mode lock, so start encapsulating things. Unfortunately this ended up in the "wrong" header file since it needs the definition of struct drm_device. v2: Drop most WARNS again - we hit them all over the place, mostly in the setup and teardown sequences. And trying to fix it up leads to nice deadlocks, since the locking in the setup code is really inconsistent. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 105 ++-- include/drm/drmP.h |5 +++ 2 files changed, 18 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d6d0072..7902d3c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -208,8 +208,6 @@ char *drm_get_connector_status_name(enum drm_connector_status status) * @ptr: object pointer, used to generate unique ID * @type: object type * - * LOCKING: - * * Create a unique identifier based on @ptr in @dev's identifier space. Used * for tracking modes, CRTCs and connectors. * @@ -247,9 +245,6 @@ again: * @dev: DRM device * @id: ID to free * - * LOCKING: - * Caller must hold DRM mode_config lock. - * * Free @id from @dev's unique identifier pool. */ static void drm_mode_object_put(struct drm_device *dev, @@ -279,9 +274,6 @@ EXPORT_SYMBOL(drm_mode_object_find); * drm_framebuffer_init - initialize a framebuffer * @dev: DRM device * - * LOCKING: - * Caller must hold mode config lock. - * * Allocates an ID for the framebuffer's parent mode object, sets its mode * functions & device file and adds it to the master fd list. * @@ -317,15 +309,12 @@ static void drm_framebuffer_free(struct kref *kref) /** * drm_framebuffer_unreference - unref a framebuffer - * - * LOCKING: - * Caller must hold mode config lock. */ void drm_framebuffer_unreference(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; DRM_DEBUG("FB ID: %d\n", fb->base.id); - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + WARN_ON(!drm_modeset_is_locked(dev)); kref_put(&fb->refcount, drm_framebuffer_free); } EXPORT_SYMBOL(drm_framebuffer_unreference); @@ -344,15 +333,13 @@ EXPORT_SYMBOL(drm_framebuffer_reference); * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * - * LOCKING: - * Caller must hold mode config lock. - * * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * it, setting it to NULL. */ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; + /* * This could be moved to drm_framebuffer_remove(), but for * debugging is nice to keep around the list of fb's that are @@ -370,9 +357,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); * drm_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove * - * LOCKING: - * Caller must hold mode config lock. - * * Scans all the CRTCs and planes in @dev's mode_config. If they're * using @fb, removes it, setting it to NULL. */ @@ -384,6 +368,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) struct drm_mode_set set; int ret; + WARN_ON(!drm_modeset_is_locked(dev)); + /* remove from any CRTC */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) { @@ -421,9 +407,6 @@ EXPORT_SYMBOL(drm_framebuffer_remove); * @crtc: CRTC object to init * @funcs: callbacks for the new CRTC * - * LOCKING: - *
[Intel-gfx] [PATCH 02/37] drm/doc: integrate drm_crtc.c kerneldoc
And do a quick pass to adjust them to the last few (years?) of changes ... This time actually compile-tested ;-) Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl |4 ++ drivers/gpu/drm/drm_crtc.c | 92 +++- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4ee2304..caab791 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1609,6 +1609,10 @@ void intel_crt_init(struct drm_device *dev) make its properties available to applications. + + KMS API Functions +!Edrivers/gpu/drm/drm_crtc.c + diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7902d3c..f22d4a7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -203,10 +203,10 @@ char *drm_get_connector_status_name(enum drm_connector_status status) } /** - * drm_mode_object_get - allocate a new identifier + * drm_mode_object_get - allocate a new modeset identifier * @dev: DRM device - * @ptr: object pointer, used to generate unique ID - * @type: object type + * @obj: object pointer, used to generate unique ID + * @obj_type: object type * * Create a unique identifier based on @ptr in @dev's identifier space. Used * for tracking modes, CRTCs and connectors. @@ -241,9 +241,9 @@ again: } /** - * drm_mode_object_put - free an identifer + * drm_mode_object_put - free a modeset identifer * @dev: DRM device - * @id: ID to free + * @object: object to free * * Free @id from @dev's unique identifier pool. */ @@ -273,6 +273,8 @@ EXPORT_SYMBOL(drm_mode_object_find); /** * drm_framebuffer_init - initialize a framebuffer * @dev: DRM device + * @fb: framebuffer to be initialized + * @funcs: ... with these functions * * Allocates an ID for the framebuffer's parent mode object, sets its mode * functions & device file and adds it to the master fd list. @@ -309,6 +311,9 @@ static void drm_framebuffer_free(struct kref *kref) /** * drm_framebuffer_unreference - unref a framebuffer + * @fb: framebuffer to unref + * + * This functions decrements the fb's refcount and frees it if it drops to zero. */ void drm_framebuffer_unreference(struct drm_framebuffer *fb) { @@ -321,6 +326,7 @@ EXPORT_SYMBOL(drm_framebuffer_unreference); /** * drm_framebuffer_reference - incr the fb refcnt + * @fb: framebuffer */ void drm_framebuffer_reference(struct drm_framebuffer *fb) { @@ -493,7 +499,7 @@ EXPORT_SYMBOL(drm_mode_remove); * @dev: DRM device * @connector: the connector to init * @funcs: callbacks for this connector - * @name: user visible name of the connector + * @connector_type: user visible type of the connector * * Initialises a preallocated connector. Connectors should be * subclassed as part of driver connector objects. @@ -1145,10 +1151,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, /** * drm_mode_getresources - get graphics configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a set of configuration description structures and return * them to the user, including CRTC, connector and framebuffer configuration. @@ -1330,10 +1335,9 @@ out: /** * drm_mode_getcrtc - get CRTC configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a CRTC configuration structure to return to the user. * @@ -1387,10 +1391,9 @@ out: /** * drm_mode_getconnector - get connector configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Construct a connector configuration structure to return to the user. * @@ -1675,7 +1678,7 @@ out: * drm_mode_setplane - set up or tear down an plane * @dev: DRM device * @data: ioctl data* - * @file_prive: DRM file info + * @file_priv: DRM file info * * Set plane info, including placement, fb, scaling, and other factors. * Or pass a NULL fb to disable. @@ -1801,10 +1804,9 @@ out: /** * drm_mode_setcrtc - set CRTC configuration - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call * * Build a new CRTC configuration based on user request. * @@ -2056,10 +2058,9 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format); /
[Intel-gfx] [PATCH 03/37] drm: add drm_modeset_lock|unlock_all
This is the first step towards introducing the new modeset locking scheme. The plan is to put helper functions into place at all the right places step-by-step, so that the final patch to switch on the new locking scheme doesn't need to touch every single driver. This helper here will serve as the shotgun solutions for all places where a more fine-grained locking isn't (yet) implemented. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c| 147 + drivers/gpu/drm/drm_crtc_helper.c |8 +- drivers/gpu/drm/drm_fb_helper.c | 20 ++--- include/drm/drm_crtc.h|3 + 4 files changed, 102 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f22d4a7..5d223af 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -37,6 +37,29 @@ #include #include +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + mutex_lock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_lock_all); + +/** + * drm_modeset_unlock_all - drop all modeset locks + * @drm: device + */ +void drm_modeset_unlock_all(struct drm_device *dev) +{ + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_unlock_all); + /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ char *fnname(int val) \ @@ -427,7 +450,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->funcs = funcs; crtc->invert_dimensions = false; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); if (ret) @@ -439,7 +462,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, dev->mode_config.num_crtc++; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -514,7 +537,7 @@ int drm_connector_init(struct drm_device *dev, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); if (ret) @@ -544,7 +567,7 @@ int drm_connector_init(struct drm_device *dev, dev->mode_config.dpms_property, 0); out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -594,7 +617,7 @@ int drm_encoder_init(struct drm_device *dev, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); if (ret) @@ -608,7 +631,7 @@ int drm_encoder_init(struct drm_device *dev, dev->mode_config.num_encoder++; out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -617,11 +640,11 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); drm_mode_object_put(dev, &encoder->base); list_del(&encoder->head); dev->mode_config.num_encoder--; - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_encoder_cleanup); @@ -633,7 +656,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, { int ret; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); if (ret) @@ -667,7 +690,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, } out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -677,7 +700,7 @@ void drm_plane_cleanup(struct drm_plane *plane) { struct drm_device *dev = plane->dev; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); kfree(plane->format_types); drm_mode_object_put(dev, &plane->base); /* if not added to a list, it must be a private plane */ @@ -685,7 +708,7 @@ void drm_plane_cleanup(struct drm_plane *plane) list_del(&plane->head); dev->mode_config.num_plane--; } - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_plane_cleanup); @@ -965,9 +988,9 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.plane_list
[Intel-gfx] [PATCH 04/37] drm/i915: rework locking for intel_dpio|sbi_read|write
Spinning for up to 200 us with interrupts locked out is not good. So let's just spin (and even that seems to be excessive). And we don't call these functions from interrupt context, so this is not required. Besides that doing anything in interrupt contexts which might take a few hundred us is a no-go. So just convert the entire thing to a mutex. Also move the mutex-grabbing out of the read/write functions (add a WARN_ON(!is_locked)) instead) since all callers are nicely grouped together. Finally the real motivation for this change: Dont grab the modeset mutex in the dpio debugfs file, we don't need that consistency. And correctness of the dpio interface is ensured with the dpio_lock. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c |4 +-- drivers/gpu/drm/i915/i915_dma.c |2 +- drivers/gpu/drm/i915/i915_drv.h |2 +- drivers/gpu/drm/i915/intel_display.c | 53 ++ 4 files changed, 25 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 58e6676..35d2ace 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1553,7 +1553,7 @@ static int i915_dpio_info(struct seq_file *m, void *data) return 0; } - ret = mutex_lock_interruptible(&dev->mode_config.mutex); + ret = mutex_lock_interruptible(&dev_priv->dpio_lock); if (ret) return ret; @@ -1582,7 +1582,7 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->dpio_lock); return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2635ee6..ad488f6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1579,7 +1579,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); spin_lock_init(&dev_priv->rps.lock); - spin_lock_init(&dev_priv->dpio_lock); + mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e2944e9..6fa0c00 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -655,7 +655,7 @@ typedef struct drm_i915_private { spinlock_t irq_lock; /* DPIO indirect register protection */ - spinlock_t dpio_lock; + struct mutex dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ u32 pipestat[2]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d303f2a..a0d8869 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -416,13 +416,11 @@ static const intel_limit_t intel_limits_vlv_dp = { u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) { - unsigned long flags; - u32 val = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock_irqsave(&dev_priv->dpio_lock, flags); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return 0; } I915_WRITE(DPIO_REG, reg); @@ -430,24 +428,20 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO read wait timed out\n"); - goto out_unlock; + return 0; } - val = I915_READ(DPIO_DATA); -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); - return val; + return I915_READ(DPIO_DATA); } static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { - unsigned long flags; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock_irqsave(&dev_priv->dpio_lock, flags); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return; } I915_WRITE(DPIO_DATA, val); @@ -456,9 +450,6 @@ static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) DRM_ERROR("DPIO write wait timed out\n"); - -out_unlock: - spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); } static void vlv_init_dpio(struct drm_device *dev) @@
[Intel-gfx] [PATCH 05/37] drm/i915: use drm_modeset_lock_all
Two exceptions: - debugfs files only read information which is not related to crtc, so can stay on the modeset_config lock. - Same holds for the edp vdd work in intel_dp.c. Add a corresponding WARN_ON and a comment next to the intel_dp struct fields for documentation. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c |2 ++ drivers/gpu/drm/i915/intel_fb.c |4 ++-- drivers/gpu/drm/i915/intel_lvds.c|4 ++-- drivers/gpu/drm/i915/intel_overlay.c | 14 +++--- drivers/gpu/drm/i915/intel_sprite.c |8 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b51043e..66ec9ca 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1052,6 +1052,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_FORCE_VDD; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b7773e5..ed7bb33 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -282,7 +282,7 @@ void intel_fb_restore_mode(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); if (ret) @@ -292,5 +292,5 @@ void intel_fb_restore_mode(struct drm_device *dev) list_for_each_entry(plane, &config->plane_list, head) plane->funcs->disable_plane(plane); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 7781069..2719665 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -586,9 +586,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, dev_priv->modeset_on_lid = 0; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, true); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return NOTIFY_OK; } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index fabe0ac..1e901c3 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1045,13 +1045,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, } if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); mutex_lock(&dev->struct_mutex); ret = intel_overlay_switch_off(overlay); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1075,7 +1075,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, goto out_free; } - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); mutex_lock(&dev->struct_mutex); if (new_bo->tiling_mode) { @@ -1157,7 +1157,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, goto out_unlock; mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); kfree(params); @@ -1165,7 +1165,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, out_unlock: mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_gem_object_unreference_unlocked(&new_bo->base); out_free: kfree(params); @@ -1241,7 +1241,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, return -ENODEV; } - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); mutex_lock(&dev->struct_mutex); ret = -EINVAL; @@ -1307,7 +1307,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, ret = 0; out_unlock: mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 827dcd4..d9f45d4c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -595,7 +595,7 @@ i
[Intel-gfx] [PATCH 06/37] drm/gma500: use drm_modeset_lock_all
Only two places: - suspend/resume - Some really strange mode validation tool with too much funny-lucking hand-rolled conversion code. Better safe than sorry, so convert both places to keep the locking semantics as much as possible. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/gma500/psb_drv.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index dd1fbfa..2bf0c92 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -476,7 +476,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, case PSB_MODE_OPERATION_MODE_VALID: umode = &arg->mode; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); @@ -525,7 +525,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, if (mode) drm_mode_destroy(dev, mode); mode_op_out: - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); return ret; default: -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 07/37] drm/ast: use drm_modeset_lock_all
Just a call to drm_helper_resume_force_mode, obviously wants full locking for that. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_drv.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 31123b6..f5f24b3 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -95,9 +95,9 @@ static int ast_drm_thaw(struct drm_device *dev) ast_post_gpu(dev); drm_mode_config_reset(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); drm_helper_resume_force_mode(dev); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); console_lock(); ast_fbdev_set_suspend(dev, 0); -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 08/37] drm/shmobile: use drm_modeset_lock_all
Only a resume method to account for. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/shmobile/shmob_drm_drv.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 1c350fc..e77f255 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -313,9 +313,9 @@ static int shmob_drm_pm_resume(struct device *dev) { struct shmob_drm_device *sdev = dev_get_drvdata(dev); - mutex_lock(&sdev->ddev->mode_config.mutex); + drm_modeset_lock_all(dev); shmob_drm_crtc_resume(&sdev->crtc); - mutex_unlock(&sdev->ddev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_kms_helper_poll_enable(sdev->ddev); return 0; -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 09/37] drm/vmgfx: use drm_modeset_lock_all
Ok, this one here is a bit more complicated, but for an RFC I've figured I can be a bit sloppy. So just convert ever mutex_lock call, including the interruptible one. Since other places (e.g. in the execbuf ioctl) take the mode_config.mutex without bothering with interruptible handling, I've figured I should be able to get away with this in a few more places ... Signed-off-by: Daniel Vetter --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 18 -- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 2f7c08e..13e4371 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -161,11 +161,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - ret = mutex_lock_interruptible(&dev->mode_config.mutex); - if (unlikely(ret != 0)) { - ret = -ERESTARTSYS; - goto out_no_mode_mutex; - } + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { @@ -198,8 +194,7 @@ out_no_surface: ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: out_no_fb: - mutex_unlock(&dev->mode_config.mutex); -out_no_mode_mutex: + drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: @@ -249,11 +244,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_no_copy; } - ret = mutex_lock_interruptible(&dev->mode_config.mutex); - if (unlikely(ret != 0)) { - ret = -ERESTARTSYS; - goto out_no_mode_mutex; - } + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { @@ -280,8 +271,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: out_no_fb: - mutex_unlock(&dev->mode_config.mutex); -out_no_mode_mutex: + drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 10/37] drm: add per-crtc locks
*drumroll* The basic idea is to protect per-crtc state which can change without touching the output configuration with separate mutexes, i.e. all the input side state to a crtc like framebuffers, cursor settings or plane configuration. Holding such a crtc lock gives a read-lock on all the other crtc state which can be changed by e.g. a modeset. All non-crtc state is still protected by the mode_config mutex. Callers that need to change modeset state of a crtc (e.g. dpms or set_mode) need to grab both the mode_config lock and nested within any crtc locks. Note that since there can only ever be one holder of the mode_config lock we can grab the subordinate crtc locks in any order (if we need to grab more than one of them). Lockdep can handle such nesting with the mutex_lock_nest_lock call correctly. With this functions that only touch connectors/encoders but not crtcs only need to take the mode_config lock. The biggest such case is the output probing, which means that we can now pageflip and move cursors while the output probe code is reading an edid. Most cases neatly fall into the three buckets: - Only touches connectors and similar output state and so only needs the mode_config lock. - Touches the global configuration and so needs all locks. - Only touches the crtc input side and so only needs the crtc lock. But a few cases that need special consideration: - Load detection which requires a crtc. The mode_config lock already prevents a modeset change, so we can use any unused crtc as we like to do load detection. The only thing to consider is that such temporary state changes don't leak out to userspace through ioctls that only take the crtc look (like a pageflip). Hence the load detect code needs to grab the crtc of any output pipes it touches (but only if it touches state used by the pageflip or cursor ioctls). - Atomic pageflip when moving planes. The first case is sane hw, where planes have a fixed association with crtcs - nothing needs to be done there. More insane^Wflexible hw needs to have plane->crtc mapping which is separately protect with a lock that nests within the crtc lock. If the plane is unused we can just assign it to the current crtc and continue. But if a plane is already in use by another crtc we can't just reassign it. Two solution present themselves: Either go back to a slow-path which takes all modeset locks, potentially incure quite a hefty delay. Or simply disallowing such changes in one atomic pageflip - in general the vblanks of two crtcs are not synced, so there's no sane way to atomically flip such plane changes accross more than one crtc. I'd heavily favour the later approach, going as far as mandating it as part of the ABI of such a new a nuclear pageflip. And if we _really_ want such semantics, we can always get them by introducing another pageflip mutex between the mode_config.mutex and the individual crtc locks. Pageflips crossing more than one crtc would then need to take that lock first, to lock out concurrent multi-crtc pageflips. - Optimized global modeset operations: We could just take the mode_config lock and then lazily lock all crtc which are affected by a modeset operation. This has the advantage that pageflip could continue unhampered on unaffected crtc. But if e.g. global resources like plls need to be reassigned and so affect unrelated crtcs we can still do that - nested locking works in any order. This patch just adds the locks and takes them in drm_modeset_lock_all, no real locking changes yet. v2: Need to initialize the new lock in crtc_init and lock it righ away, for otherwise the modeset_unlock_all below will try to unlock a not-locked mutex. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 12 include/drm/drm_crtc.h |9 + 2 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5d223af..91e8068 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -46,7 +46,12 @@ */ void drm_modeset_lock_all(struct drm_device *dev) { + struct drm_crtc *crtc; + mutex_lock(&dev->mode_config.mutex); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); } EXPORT_SYMBOL(drm_modeset_lock_all); @@ -56,6 +61,11 @@ EXPORT_SYMBOL(drm_modeset_lock_all); */ void drm_modeset_unlock_all(struct drm_device *dev) { + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + mutex_unlock(&crtc->mutex); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_modeset_unlock_all); @@ -451,6 +461,8 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->invert_dimensions = false; drm_modeset_lock_all(dev); + mutex_init(&crtc->mutex); + mutex_lock_nest_lock(&crtc-
[Intel-gfx] [PATCH 17/37] drm: revamp locking around fb creation/destruction
Well, at least step 1. The goal here is that framebuffer objects can survive outside of the mode_config lock, with just a reference held as protection. The first step to get there is to introduce a special fb_lock which protects fb lookup, creation and destruction, to make them appear atomic. This new fb_lock can nest within the mode_config lock. But the idea is (once the reference counting part is completed) that we only quickly take that fb_lock to lookup a framebuffer and grab a reference, without any other locks involved. vmwgfx is the only driver which does framebuffer lookups itself, also wrap those calls to drm_mode_object_find with the new lock. Also protect the fb_list walking in i915 and omapdrm with the new lock. As a slight complication there's also the list of user-created fbs attached to the file private. The problem now is that at fclose() time we need to walk that list, eventually do a modeset call to remove the fb from active usage (and are required to be able to take the mode_config lock), but in the end we need to grab the new fb_lock to remove the fb from the list. The easiest solution is to add another mutex to protect this per-file list. Currently that new fbs_lock nests within the modeset locks and so appears redudant. But later patches will switch around this sequence so that taking the modeset locks in the fb destruction path is optional in the fastpath. Ultimately the goal is that addfb and rmfb do not require the mode_config lock, since otherwise they have the potential to introduce stalls in the pageflip sequence of a compositor (if the compositor e.g. switches to a fullscreen client or if it enables a plane). But that requires a few more steps and hoops to jump through. Note that framebuffer creation/destruction is now double-protected - once by the fb_lock and in parts by the idr_lock. The later would be unnecessariy if framebuffers would have their own idr allocator. But that's material for another patch (series). v2: Properly initialize the fb->filp_head list in _init, otherwise the newly added WARN to check whether the fb isn't on a fpriv list any more will fail for driver-private objects. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 113 ++-- drivers/gpu/drm/drm_fops.c |1 + drivers/gpu/drm/i915/i915_debugfs.c|5 +- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |4 ++ drivers/staging/omapdrm/omap_debugfs.c |2 + include/drm/drmP.h |8 +++ include/drm/drm_crtc.h | 14 7 files changed, 111 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3b2f25d..5a46ea1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -262,15 +262,21 @@ again: mutex_lock(&dev->mode_config.idr_mutex); ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); + + if (!ret) { + /* +* Set up the object linking under the protection of the idr +* lock so that other users can't see inconsistent state. +*/ + obj->id = new_id; + obj->type = obj_type; + } mutex_unlock(&dev->mode_config.idr_mutex); + if (ret == -EAGAIN) goto again; - else if (ret) - return ret; - obj->id = new_id; - obj->type = obj_type; - return 0; + return ret; } /** @@ -312,6 +318,12 @@ EXPORT_SYMBOL(drm_mode_object_find); * Allocates an ID for the framebuffer's parent mode object, sets its mode * functions & device file and adds it to the master fd list. * + * IMPORTANT: + * This functions publishes the fb and makes it available for concurrent access + * by other users. Which means by this point the fb _must_ be fully set up - + * since all the fb attributes are invariant over its lifetime, no further + * locking but only correct reference counting is required. + * * RETURNS: * Zero on success, error code on failure. */ @@ -320,16 +332,19 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, { int ret; + mutex_lock(&dev->mode_config.fb_lock); kref_init(&fb->refcount); + INIT_LIST_HEAD(&fb->filp_head); + fb->dev = dev; + fb->funcs = funcs; ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); if (ret) return ret; - fb->dev = dev; - fb->funcs = funcs; dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); + mutex_unlock(&dev->mode_config.fb_lock); return 0; } @@ -387,8 +402,10 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) * this.) */ drm_mode_object_put(dev, &fb->base); + mutex_lock(&dev->mode_config.fb_lock); list_del(&fb->head); dev->mode_config.num_fb--; + mute
[Intel-gfx] [PATCH 36/37] drm: only grab the crtc lock for pageflips
The pagelip ioctl itself is rather simply, so the hard work for this patch is auditing all the drivers: - exynos: Pageflip is protect with dev->struct_mutex and ... synchronous. But nothing fancy going on, besides a check whether the crtc is enabled, which should probably be somewhere in the drm core so that we have unified behaviour across all drivers. - i915: hw-state is protected with dev->struct_mutex, the delayed unpin work together with the other stuff the pageflip complete irq handler needs is protected by the event_lock spinlock. - nouveau: With the pin/unpin functions fixed, everything looks safe: A bit of ttm wrestling and refcounting, and a few channel accesses. The later are either already proteced sufficiently, or are now safe with the channel locking introduced to make cursor updates safe. - radeon: The irq_get/put functions look a bit race, since the atomic_inc/dec isn't protect with locks. Otoh they're all per-crtc, so we should be safe with per-crtc locking from the drm core. Then there's tons of per-crtc register access, which could potentially go through the indirect reg acces. But that's fixed to make cursor updates concurrent. Bookeeping for the drm even is also protected with the even_lock, which also protects against the pageflip irq handler since radeon hw seems to have no way to queue these up asynchronously. Otherwise just a bit of ttm-based buffer handling and fencing, which is now safe with the previous patch to hold bdev->fence_lock while grabbing the ttm fence. - shmob: Only one crtc. That's an easy one ... - vmwgfx: As usual a bit special with tons different things: - Flippable check using is_implicit and num_implicit. Changes to those seem to be nicely covered with the global modeset lock, so we should be fine. - Some dirty cliprect handling stuff, or at least that is my guess. Looks like it's fine since either it's per-crtc, invariant or (like the execbuf stuff launched) protected otherwise. - Adding the actual flip to the fence_event list. On a quick look this seems to have solid locking in place, too. ... but generally this is all way over my head. - imx: Impressive display of races between the page_flip implementation and the irq handler. Also, ipu_drm_set_base which gets eventually called from the irq handler to update the display base isn't really protected against concurrent set_config calls from process context. In any case, going for per-crtc locking won't make this worse, so nothing to do. - omap: Does just some prep work on per-crtc data and grabs a ref on the backing storage, then calls down into omap_gem_op_async which does some nicely-protected async callback stuff, or directly calls the passed-in page_flip_cb. That seems to lock most of the stuff it touches properly, safe for the eventually called omap_plane_dpms, which updates modeset state. Which will be a problem if this is called asynchronously, since the sync_op waiter callback code in omap_gem.c does not seem to take the right modeset locks. So looks a bit racy already with the old locking, and no worse off with the new per-crtc locks. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6dd441c..36c75e6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3716,12 +3716,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, page_flip->reserved != 0) return -EINVAL; - drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) - goto out; + return -EINVAL; crtc = obj_to_crtc(obj); + mutex_lock(&crtc->mutex); if (crtc->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not @@ -3803,7 +3803,8 @@ out: drm_framebuffer_unreference(fb); if (old_fb) drm_framebuffer_unreference(old_fb); - drm_modeset_unlock_all(dev); + mutex_unlock(&crtc->mutex); + return ret; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 37/37] drm: don't hold crtc mutexes for connector ->detect callbacks
The coup de grace of the entire journey. No more dropped frames every 10s on my testbox! I've tried to audit all ->detect and ->get_modes callbacks, but things became a bit fuzzy after trying to piece together the umpteenth implemenation. Afaict most drivers just have bog-standard output register frobbing with a notch of i2c edid reading, nothing which could potentially race with the newly concurrent pageflip/set_cursor code. The big exception is load-detection code which requires a running pipe, but radeon/nouveau seem to to this without touching any state which can be observed from page_flip (e.g. disabled crtcs temporarily getting enabled and so a pageflip succeeding). The only special case I could find is the i915 load detect code. That uses the normal modeset interface to enable the load-detect crtc, and so userspace could try to squeeze in a pageflip on the load-detect pipe. So we need to grab the relevant crtc mutex in there, to avoid the temporary crtc enabling to sneak out and be visible to userspace. Note that the sysfs files already stopped grabbing the per-crtc locks, since I didn't want to bother with doing a interruptible modeset_lock_all. But since there's very little in-between breakage (essentially just the ability for userspace to pageflip on load-detect crtcs when it shouldn't on the i915 driver) I figured I don't need to bother. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |5 +++-- drivers/gpu/drm/drm_crtc_helper.c|8 drivers/gpu/drm/i915/intel_display.c | 10 -- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 36c75e6..313d7d2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1616,7 +1616,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); - drm_modeset_lock_all(dev); + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); @@ -1713,7 +1713,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->count_encoders = encoders_count; out: - drm_modeset_unlock_all(dev); + mutex_unlock(&dev->mode_config.mutex); + return ret; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 400ef86..7b2d378 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -980,7 +980,7 @@ static void output_poll_execute(struct work_struct *work) if (!drm_kms_helper_poll) return; - drm_modeset_lock_all(dev); + mutex_lock(&dev->mode_config.mutex); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { /* Ignore forced connectors. */ @@ -1010,7 +1010,7 @@ static void output_poll_execute(struct work_struct *work) changed = true; } - drm_modeset_unlock_all(dev); + mutex_unlock(&dev->mode_config.mutex); if (changed) drm_kms_helper_hotplug_event(dev); @@ -1070,7 +1070,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) if (!dev->mode_config.poll_enabled) return; - drm_modeset_lock_all(dev); + mutex_lock(&dev->mode_config.mutex); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { /* Only handle HPD capable connectors. */ @@ -1088,7 +1088,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) changed = true; } - drm_modeset_unlock_all(dev); + mutex_unlock(&dev->mode_config.mutex); if (changed) drm_kms_helper_hotplug_event(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd8cfeb..2429d39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6390,6 +6390,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, if (encoder->crtc) { crtc = encoder->crtc; + mutex_lock(&crtc->mutex); + old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -6419,6 +6421,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, return false; } + mutex_lock(&crtc->mutex); intel_encoder->new_crtc = to_intel_crtc(crtc); to_intel_connector(connector)->new_encoder = intel_encoder; @@ -6446,6 +6449,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); + mutex_unloc
[Intel-gfx] [PATCH 25/37] drm: don't take modeset locks in getfb ioctl
We only need to push the fb unreference a bit down. While at it, properly pass the return value from ->create_handle back to userspace. Most drivers either return -ENODEV if they don't have a concept of buffer objects (ast, cirrus, ...) or just install a handle for the underlying gem object (which is ok since we hold a reference on that through the framebuffer). But a few drivers needed tiny fixups: - cirrus/ast/mga200: Return a consistent -ENODEV to signal to userspace that these drivers don't bother with implementing the ->create_handle callback, since it's rather pointless for them to do so with no accel support. - udl: Didn't even bother with a callback, leading to a nice userspace-triggerable OOPS. Nice work. Fix this up and return -ENODEV like the other simple drivers. It could be somewhat useful to implement the real ->create_handle since udl buffers could be used with prime, but alas ... - vmwgfx: This driver bothered with an implementation to return 0 as the handle (which is the canonical nofb handle). Dunno what this is for, but I've lost myself in vmwgfx too often. Just leave this as-is. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_main.c |2 +- drivers/gpu/drm/cirrus/cirrus_main.c |2 +- drivers/gpu/drm/drm_crtc.c | 17 ++--- drivers/gpu/drm/mgag200/mgag200_main.c |2 +- drivers/gpu/drm/udl/udl_fb.c |9 - 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index d5ba709..a94f13e 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -250,7 +250,7 @@ static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file, unsigned int *handle) { - return -EINVAL; + return -ENODEV; } static const struct drm_framebuffer_funcs ast_fb_funcs = { diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 2eac87b..e9de084 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -27,7 +27,7 @@ static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { - return 0; + return -NODEV; } static const struct drm_framebuffer_funcs cirrus_fb_funcs = { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9ad807d..28838cf 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2526,29 +2526,24 @@ int drm_mode_getfb(struct drm_device *dev, { struct drm_mode_fb_cmd *r = data; struct drm_framebuffer *fb; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, r->fb_id); - if (!fb) { - ret = -EINVAL; - goto out; - } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); + if (!fb) + return -EINVAL; r->height = fb->height; r->width = fb->width; r->depth = fb->depth; r->bpp = fb->bits_per_pixel; r->pitch = fb->pitches[0]; - fb->funcs->create_handle(fb, file_priv, &r->handle); + ret = fb->funcs->create_handle(fb, file_priv, &r->handle); + + drm_framebuffer_unreference(fb); -out: - drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index 266438a..90fd681 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -27,7 +27,7 @@ static int mga_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { - return 0; + return -ENODEV; } static const struct drm_framebuffer_funcs mga_fb_funcs = { diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index c09c04e..cb61ff7 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -419,10 +419,17 @@ static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb) kfree(ufb); } +static int udl_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + return -ENODEV; +} + static const struct drm_framebuffer_funcs udlfb_funcs = { .destroy = udl_user_framebuffer_destroy,
[Intel-gfx] [PATCH 34/37] drm/ttm: fix fence locking in ttm_buffer_object_transfer
Noticed while reviewing the fence locking in the radone pageflip handler. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ttm/ttm_bo_util.c |2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index b9c4e51..5c8b207 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -441,7 +441,9 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, fbo->vm_node = NULL; atomic_set(&fbo->cpu_writers, 0); + spin_lock(&bdev->fence_lock); fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); + spin_unlock(&bdev->fence_lock); kref_init(&fbo->list_kref); kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 13/37] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex
With per-crtc locks modeset operations can run in parallel, and the cursor code uses the device-global evo master channel for hw frobbing. But the pageflip code can also sync with the master under some circumstances. Hence just wrap things up in a mutex to ensure that pushbuf access doesn't intermingle. The approach here is a bit overkill since the per-crtc channels used to schedule the pageflips could probably be used without this pushbuf locking, but I'm not familiar enough with the nouveau codebase to be sure of that. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/nouveau/nv50_display.c |8 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 3587408..5751d63 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -128,6 +128,11 @@ struct nv50_dmac { struct nv50_chan base; dma_addr_t handle; u32 *ptr; + + /* Protects against concurrent pushbuf access to this channel, lock is +* grabbed by evo_wait (if the pushbuf reservation is successful) and +* dropped again by evo_kick. */ + struct mutex lock; }; static void @@ -395,11 +400,13 @@ evo_wait(void *evoc, int nr) struct nv50_dmac *dmac = evoc; u32 put = nv_ro32(dmac->base.user, 0x) / 4; + mutex_lock(&dmac->lock); if (put + nr >= (PAGE_SIZE / 4) - 8) { dmac->ptr[put] = 0x2000; nv_wo32(dmac->base.user, 0x, 0x); if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x)) { + mutex_unlock(&dmac->lock); NV_ERROR(dmac->base.user, "channel stalled\n"); return NULL; } @@ -415,6 +422,7 @@ evo_kick(u32 *push, void *evoc) { struct nv50_dmac *dmac = evoc; nv_wo32(dmac->base.user, 0x, (push - dmac->ptr) << 2); + mutex_unlock(&dmac->lock); } #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 31/37] drm/vmwgfx: add proper framebuffer refcounting
Afact vmwgfx already has all the right refcounting implemented on the backing storage, and we only need to ensure that the drm fb doesn't disappear untimely. So holding onto the fb reference from _lookup until vmw_kms_present has completed should be enough. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |8 +++- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 4a73e9e..4a16b79 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -169,8 +169,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_no_fb; } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); vfb = vmw_framebuffer_to_vfb(fb); ret = ttm_read_lock(&vmaster->lock, true); @@ -195,6 +193,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, out_no_surface: ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: + drm_framebuffer_unreference(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: @@ -254,14 +253,12 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_no_fb; } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); vfb = vmw_framebuffer_to_vfb(fb); if (!vfb->dmabuf) { DRM_ERROR("Framebuffer not dmabuf backed.\n"); ret = -EINVAL; - goto out_no_fb; + goto out_no_ttm_lock; } ret = ttm_read_lock(&vmaster->lock, true); @@ -274,6 +271,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: + drm_framebuffer_unreference(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 18/37] drm: create drm_framebuffer_lookup
And replace all fb lookups with it. Also add a WARN to drm_mode_object_find since that is now no longer the blessed interface to look up an fb. And add kerneldoc to both functions. This only updates all callsites, but immediately drops the acquired refence again. Hence all callers still rely on the fact that a mode fb can't disappear while they're holding the struct mutex. Subsequent patches will instate proper use of refcounts, and then rework the rmfb and unref code to no longer serialize fb destruction with the mode_config lock. We don't want that since otherwise a compositor might end up stalling for a few frames in rmfb. v2: Don't use kreg_get_unless_zero - Greg KH doesn't like that kind of interface. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c| 109 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 24 include/drm/drm_crtc.h|2 + 3 files changed, 86 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5a46ea1..75ffc3b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -294,11 +294,24 @@ static void drm_mode_object_put(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); } +/** + * drm_mode_object_find - look up a drm object with static lifetime + * @dev: drm device + * @id: id of the mode object + * @type: type of the mode object + * + * Note that framebuffers cannot be looked up with this functions - since those + * are reference counted, they need special treatment. + */ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj = NULL; + /* Framebuffers are reference counted and need their own lookup +* function.*/ + WARN_ON(type == DRM_MODE_OBJECT_FB); + mutex_lock(&dev->mode_config.idr_mutex); obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) @@ -358,6 +371,40 @@ static void drm_framebuffer_free(struct kref *kref) } /** + * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference + * @dev: drm device + * @id: id of the fb object + * + * If successful, this grabs an additional reference to the framebuffer - + * callers need to make sure to eventually unreference the returned framebuffer + * again. + */ +struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *obj = NULL; + struct drm_framebuffer *fb; + + mutex_lock(&dev->mode_config.fb_lock); + + mutex_lock(&dev->mode_config.idr_mutex); + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) + fb = NULL; + else + fb = obj_to_fb(obj); + mutex_unlock(&dev->mode_config.idr_mutex); + + if (fb) + kref_get(&fb->refcount); + + mutex_unlock(&dev->mode_config.fb_lock); + + return fb; +} +EXPORT_SYMBOL(drm_framebuffer_lookup); + +/** * drm_framebuffer_unreference - unref a framebuffer * @fb: framebuffer to unref * @@ -1789,17 +1836,15 @@ int drm_mode_setplane(struct drm_device *dev, void *data, } crtc = obj_to_crtc(obj); - mutex_lock(&dev->mode_config.fb_lock); - obj = drm_mode_object_find(dev, plane_req->fb_id, - DRM_MODE_OBJECT_FB); - mutex_unlock(&dev->mode_config.fb_lock); - if (!obj) { + fb = drm_framebuffer_lookup(dev, plane_req->fb_id); + if (!fb) { DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", plane_req->fb_id); ret = -ENOENT; goto out; } - fb = obj_to_fb(obj); + /* fb is protect by the mode_config lock, so drop the ref immediately */ + drm_framebuffer_unreference(fb); /* Check whether this plane supports the fb pixel format. */ for (i = 0; i < plane->format_count; i++) @@ -1919,17 +1964,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, } fb = crtc->fb; } else { - mutex_lock(&dev->mode_config.fb_lock); - obj = drm_mode_object_find(dev, crtc_req->fb_id, - DRM_MODE_OBJECT_FB); - mutex_unlock(&dev->mode_config.fb_lock); - if (!obj) { + fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); + if (!fb) { DRM_DEBUG_KMS("Unknown FB ID%d\n", crtc_req->fb_id); ret = -EINVAL; goto out;
[Intel-gfx] [PATCH 19/37] drm/gma500: move fbcon restore to lastclose
Doing this within the fb->destroy callback leads to a locking nightmare. And all other drm drivers that restore the fbcon do it in lastclose, too. With this adjustments all fb->destroy callbacks optionally drop references to any gem objects used as backing storage, call drm_framebuffer_cleanup and then kfree the struct. Which nicely simplifies the locking for framebuffer unreferencing and freeing, since this doesn't require that we hold the mode_config lock. A slight exception is the vmwgfx surface backed framebuffer, it also calls drm_master_put and removes the object from a device-private framebuffer list. Both seem to have solid locking in place already. Conclusion is that now it is no longer required to hold the mode_config lock while freeing a framebuffer. v2: Drop the corresponding mutex_lock WARN check from drm_framebuffer_unreference. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |2 -- drivers/gpu/drm/gma500/framebuffer.c | 24 drivers/gpu/drm/gma500/psb_drv.c | 11 +++ 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 75ffc3b..17cdd32 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -412,9 +412,7 @@ EXPORT_SYMBOL(drm_framebuffer_lookup); */ void drm_framebuffer_unreference(struct drm_framebuffer *fb) { - struct drm_device *dev = fb->dev; DRM_DEBUG("FB ID: %d\n", fb->base.id); - WARN_ON(!drm_modeset_is_locked(dev)); kref_put(&fb->refcount, drm_framebuffer_free); } EXPORT_SYMBOL(drm_framebuffer_unreference); diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 38e7e75..49800d2 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -668,30 +668,6 @@ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct psb_framebuffer *psbfb = to_psb_fb(fb); struct gtt_range *r = psbfb->gtt; - struct drm_device *dev = fb->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_fbdev *fbdev = dev_priv->fbdev; - struct drm_crtc *crtc; - int reset = 0; - - /* Should never get stolen memory for a user fb */ - WARN_ON(r->stolen); - - /* Check if we are erroneously live */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - if (crtc->fb == fb) - reset = 1; - - if (reset) - /* -* Now force a sane response before we permit the DRM CRTC -* layer to do stupid things like blank the display. Instead -* we reset this framebuffer as if the user had forced a reset. -* We must do this before the cleanup so that the DRM layer -* doesn't get a chance to stick its oar in where it isn't -* wanted. -*/ - drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); /* Let DRM do its clean up */ drm_framebuffer_cleanup(fb); diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 2bf0c92..5518305 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -149,6 +149,17 @@ static struct drm_ioctl_desc psb_ioctls[] = { static void psb_lastclose(struct drm_device *dev) { + int ret; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_fbdev *fbdev = dev_priv->fbdev; + + drm_modeset_lock_all(dev); + ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); + + drm_modeset_unlock_all(dev); + return; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 27/37] drm: refcounting for sprite framebuffers
Now plane->fb holds a reference onto it's framebuffer. Nothing too fancy going on here: - Extract __drm_framebuffer_unreference to be called when we know we're not dropping the last reference, e.g. useful in the fb cleanup code. - Reduce the locked sections in the set_plane ioctl to only protect plane->fb/plane->crtc and the driver callback (i.e. hw state). Everything either doesn't disappear (crtc, plane) or is refcounted (fb), and all the data we check is invariant over the respective object's lifetimes. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 30 +- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8132e13..ccf15ad 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -444,6 +444,12 @@ static void drm_framebuffer_free_bug(struct kref *kref) BUG(); } +static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_put(&fb->refcount, drm_framebuffer_free_bug); +} + /* dev->mode_config.fb_lock must be held! */ static void __drm_framebuffer_unregister(struct drm_device *dev, struct drm_framebuffer *fb) @@ -454,7 +460,7 @@ static void __drm_framebuffer_unregister(struct drm_device *dev, fb->base.id = 0; - kref_put(&fb->refcount, drm_framebuffer_free_bug); + __drm_framebuffer_unreference(fb); } /** @@ -543,6 +549,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) if (ret) DRM_ERROR("failed to disable plane with busy fb\n"); /* disconnect the plane from the fb and crtc: */ + __drm_framebuffer_unreference(plane->fb); plane->fb = NULL; plane->crtc = NULL; } @@ -1849,7 +1856,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, struct drm_mode_object *obj; struct drm_plane *plane; struct drm_crtc *crtc; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL, *old_fb = NULL; int ret = 0; unsigned int fb_width, fb_height; int i; @@ -1857,8 +1864,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); - /* * First, find the plane, crtc, and fb objects. If not available, * we don't bother to call the driver. @@ -1868,16 +1873,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown plane ID %d\n", plane_req->plane_id); - ret = -ENOENT; - goto out; + return -ENOENT; } plane = obj_to_plane(obj); /* No fb means shut it down */ if (!plane_req->fb_id) { + drm_modeset_lock_all(dev); + old_fb = plane->fb; plane->funcs->disable_plane(plane); plane->crtc = NULL; plane->fb = NULL; + drm_modeset_unlock_all(dev); goto out; } @@ -1898,8 +1905,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, ret = -ENOENT; goto out; } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); /* Check whether this plane supports the fb pixel format. */ for (i = 0; i < plane->format_count; i++) @@ -1945,18 +1950,25 @@ int drm_mode_setplane(struct drm_device *dev, void *data, goto out; } + drm_modeset_lock_all(dev); ret = plane->funcs->update_plane(plane, crtc, fb, plane_req->crtc_x, plane_req->crtc_y, plane_req->crtc_w, plane_req->crtc_h, plane_req->src_x, plane_req->src_y, plane_req->src_w, plane_req->src_h); if (!ret) { + old_fb = plane->fb; + fb = NULL; plane->crtc = crtc; plane->fb = fb; } + drm_modeset_unlock_all(dev); out: - drm_modeset_unlock_all(dev); + if (fb) + drm_framebuffer_unreference(fb); + if (old_fb) + drm_framebuffer_unreference(old_fb); return ret; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 24/37] drm: push modeset_lock_all into ->fb_create driver callbacks
And drop it where it's not needed. Most driver just lookup the gem object, allocate an fb struct, fill in all the useful fields and then register it with drm_framebuffer_init. All of these operations are already separately locked, and since we only put the fb into the fpriv->fbs list _after_ having called ->fb_create, we can't also race with rmfb. We can otoh race with other ioctls that put the framebuffer to use, but all drivers have been reorganized already to call drm_framebuffer_init last in the fb creation sequence. So essentially, we can completely remove any modeset locks from the addfb ioctl paths. Yeah! Also, reference-counting is solid - we get a reference from fb_create which we transfer to the fpriv->fbs list. And after unlocking the fpriv->fbs_lock we don't touch the framebuffer any longer. Furthermore drm_framebuffer_init has added a 2nd reference for the idr lookup, and any access through that table will do it's own refcounting. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |9 - 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 33e95bb..9ad807d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2255,18 +2255,12 @@ int drm_mode_addfb(struct drm_device *dev, if ((config->min_height > r.height) || (r.height > config->max_height)) return -EINVAL; - drm_modeset_lock_all(dev); - - /* TODO check buffer is sufficiently large */ - /* TODO setup destructor callback */ - fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); drm_modeset_unlock_all(dev); return PTR_ERR(fb); } - drm_modeset_unlock_all(dev); mutex_lock(&file_priv->fbs_lock); or->fb_id = fb->base.id; @@ -2441,15 +2435,12 @@ int drm_mode_addfb2(struct drm_device *dev, if (ret) return ret; - drm_modeset_lock_all(dev); - fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); drm_modeset_unlock_all(dev); return PTR_ERR(fb); } - drm_modeset_unlock_all(dev); mutex_lock(&file_priv->fbs_lock); r->fb_id = fb->base.id; -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 23/37] drm/i915: fixup overlay stolen memory leak
We need to clean up the overlay first, before taking down the stolen memory allocator. This regression has been introducec in commit 8040513870399f1cb032cb8bc805df5042fedcdf Author: Chris Wilson Date: Thu Nov 15 11:32:29 2012 + drm/i915: Allocate overlay registers from stolen memory Note: This is just a quick hack to shut up a warning in the module unload code, so that I can check again whether we don't leak any framebuffers. Cc: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ad488f6..532ad39 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1720,9 +1720,9 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); i915_gem_cleanup_stolen(dev); - drm_mm_takedown(&dev_priv->mm.stolen); intel_cleanup_overlay(dev); + drm_mm_takedown(&dev_priv->mm.stolen); if (!I915_NEED_GFX_HWS(dev)) i915_free_hws(dev); -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 32/37] drm: optimize drm_framebuffer_remove
Now that all framebuffer usage is properly refcounted, we are no longer required to hold the modeset locks while dropping the last reference. Hence implemented a fastpath which avoids the potential stalls associated with grabbing mode_config.lock for the case where there's no other reference around. Explain in a big comment why it is safe. Also update kerneldocs with the new locking rules around drm_framebuffer_remove. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 72 +++- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6562eba..6dd441c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -516,7 +516,11 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); * * Scans all the CRTCs and planes in @dev's mode_config. If they're * using @fb, removes it, setting it to NULL. Then drops the reference to the - * passed-in framebuffer. + * passed-in framebuffer. Might take the modeset locks. + * + * Note that this function optimizes the cleanup away if the caller holds the + * last reference to the framebuffer. It is also guaranteed to not take the + * modeset locks in this case. */ void drm_framebuffer_remove(struct drm_framebuffer *fb) { @@ -526,33 +530,51 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) struct drm_mode_set set; int ret; - WARN_ON(!drm_modeset_is_locked(dev)); WARN_ON(!list_empty(&fb->filp_head)); - /* remove from any CRTC */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) { - /* should turn off the crtc */ - memset(&set, 0, sizeof(struct drm_mode_set)); - set.crtc = crtc; - set.fb = NULL; - ret = drm_mode_set_config_internal(&set); - if (ret) - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + /* +* drm ABI mandates that we remove any deleted framebuffers from active +* useage. But since most sane clients only remove framebuffers they no +* longer need, try to optimize this away. +* +* Since we're holding a reference ourselves, observing a refcount of 1 +* means that we're the last holder and can skip it. Also, the refcount +* can never increase from 1 again, so we don't need any barriers or +* locks. +* +* Note that userspace could try to race with use and instate a new +* usage _after_ we've cleared all current ones. End result will be an +* in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot +* in this manner. +*/ + if (atomic_read(&fb->refcount.refcount) > 1) { + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) { + /* should turn off the crtc */ + memset(&set, 0, sizeof(struct drm_mode_set)); + set.crtc = crtc; + set.fb = NULL; + ret = drm_mode_set_config_internal(&set); + if (ret) + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + } } - } - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - if (plane->fb == fb) { - /* should turn off the crtc */ - ret = plane->funcs->disable_plane(plane); - if (ret) - DRM_ERROR("failed to disable plane with busy fb\n"); - /* disconnect the plane from the fb and crtc: */ - __drm_framebuffer_unreference(plane->fb); - plane->fb = NULL; - plane->crtc = NULL; + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + if (plane->fb == fb) { + /* should turn off the crtc */ + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("failed to disable plane with busy fb\n"); + /* disconnect the plane from the fb and crtc: */ + __drm_framebuffer_unreference(plane->fb); + plane->fb = NULL; + plane->crtc = NULL; + } } + drm_modeset_unlock_all(dev); } drm_framebuffer_unr
[Intel-gfx] [PATCH 15/37] drm: only take the crtc lock for ->cursor_move
->cursor_move uses mostly the same facilities in drivers as ->cursor_set, so pretty much nothing to fix up: - ast/gma500/i915: They all use per-crtc registers to update the cursor position. ast again touches the global cursor cache, but that's ok since there's only one crtc. - nouveau: nv50+ is again special, updates happen through the per-crtc channel (without pushbufs), so it's not protected by the new evo lock introduced earlier. But since this channel is per-crtc, we should be fine anyway. - radeon: A bit a mess: avivo asics need a workaround when both output pipes are enabled, which means it'll access the crtc list. Just reading that flag is ok though as long as radeon _always_ grabs all locks when changing the crtc configuration. Which means with the current scheme it cannot do an optimized modeset which only locks the relevant crtcs. This can be fixed though by introducing a bit of global state with separate locks and ensure in the modeset code that the cursor will be updated appropriately when enabling the 2nd pipe (on affected asics). - vmwgfx: I still don't understand what it's doing exactly, so apply the same trick for now. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |6 ++ drivers/gpu/drm/radeon/radeon_cursor.c |8 +++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c| 13 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 62b5002..3b2f25d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2031,28 +2031,26 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, } crtc = obj_to_crtc(obj); + mutex_lock(&crtc->mutex); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set) { ret = -ENXIO; goto out; } /* Turns off the cursor if handle is 0 */ - mutex_lock(&crtc->mutex); ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); - mutex_unlock(&crtc->mutex); } if (req->flags & DRM_MODE_CURSOR_MOVE) { if (crtc->funcs->cursor_move) { - drm_modeset_lock_all(dev); ret = crtc->funcs->cursor_move(crtc, req->x, req->y); - drm_modeset_unlock_all(dev); } else { ret = -EFAULT; goto out; } } + mutex_unlock(&crtc->mutex); out: return ret; } diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index ad6df62..c1680e6 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -245,8 +245,14 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, int i = 0; struct drm_crtc *crtc_p; - /* avivo cursor image can't end on 128 pixel boundary or + /* +* avivo cursor image can't end on 128 pixel boundary or * go past the end of the frame if both crtcs are enabled +* +* NOTE: It is safe to access crtc->enabled of other crtcs +* without holding either the mode_config lock or the other +* crtc's lock as long as write access to this flag _always_ +* grabs all locks. */ list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { if (crtc_p->enabled) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 74b6734..385b8849 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -264,10 +264,23 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) du->cursor_x = x + crtc->x; du->cursor_y = y + crtc->y; + /* +* FIXME: Unclear whether there's any global state touched by the +* cursor_set function, especially vmw_cursor_update_position looks +* suspicious. For now take the easy route and reacquire all locks. We +* can do this since the caller in the drm core doesn't check anything +* which is protected by any looks. +*/ + mutex_unlock(&crtc->mutex); + drm_modeset_lock_all(dev_priv->dev); + vmw_cursor_update_position(dev_priv, shown, du->cursor_x + du->hotspot_x, du->cursor_y + du->hotspot_y); + drm_modeset_unlock_all(dev_priv->dev); + mutex_lock(&crtc->mutex); + return 0; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.free
[Intel-gfx] [PATCH 30/37] drm/i915: dump refcount into framebuffer debugfs file
Useful for checking whether the new refcounting works as advertised. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index da1c8b6..e2dc77c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1369,11 +1369,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) ifbdev = dev_priv->fbdev; fb = to_intel_framebuffer(ifbdev->helper.fb); - seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ", + seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ", fb->base.width, fb->base.height, fb->base.depth, - fb->base.bits_per_pixel); + fb->base.bits_per_pixel, + atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); seq_printf(m, "\n"); mutex_unlock(&dev->mode_config.mutex); @@ -1383,11 +1384,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) if (&fb->base == ifbdev->helper.fb) continue; - seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ", + seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ", fb->base.width, fb->base.height, fb->base.depth, - fb->base.bits_per_pixel); + fb->base.bits_per_pixel, + atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); seq_printf(m, "\n"); } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 29/37] drm: refcounting for crtc framebuffers
With the prep patch to encapsulate ->set_crtc calls, this is now rather easy. Hooray for inconsistent semantics between ->set_crtc and ->page_flip, where the driver callback is supposed to update the fb pointer, and ->update_plane, where the drm core does the same. Also, since the drm core functions check crtc->fb before calling into driver callbacks, we can't really reduce the critical sections protected by the mode_config locks. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 37 ++--- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 229853e..6562eba 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1983,8 +1983,21 @@ out: int drm_mode_set_config_internal(struct drm_mode_set *set) { struct drm_crtc *crtc = set->crtc; + struct drm_framebuffer *fb, *old_fb; + int ret; + + old_fb = crtc->fb; + fb = set->fb; - return crtc->funcs->set_config(set); + ret = crtc->funcs->set_config(set); + if (ret == 0) { + if (old_fb) + drm_framebuffer_unreference(old_fb); + if (fb) + drm_framebuffer_reference(fb); + } + + return ret; } EXPORT_SYMBOL(drm_mode_set_config_internal); @@ -2045,6 +2058,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } fb = crtc->fb; + /* Make refcounting symmetric with the lookup path. */ + drm_framebuffer_reference(fb); } else { fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); if (!fb) { @@ -2053,9 +2068,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = -EINVAL; goto out; } - /* fb is protect by the mode_config lock, so drop the -* ref immediately */ - drm_framebuffer_unreference(fb); } mode = drm_mode_create(dev); @@ -2155,6 +2167,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = drm_mode_set_config_internal(&set); out: + if (fb) + drm_framebuffer_unreference(fb); + kfree(connector_set); drm_mode_destroy(dev, mode); drm_modeset_unlock_all(dev); @@ -3673,7 +3688,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_mode_crtc_page_flip *page_flip = data; struct drm_mode_object *obj; struct drm_crtc *crtc; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL, *old_fb = NULL; struct drm_pending_vblank_event *e = NULL; unsigned long flags; int hdisplay, vdisplay; @@ -3704,8 +3719,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, fb = drm_framebuffer_lookup(dev, page_flip->fb_id); if (!fb) goto out; - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); hdisplay = crtc->mode.hdisplay; vdisplay = crtc->mode.vdisplay; @@ -3751,6 +3764,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, (void (*) (struct drm_pending_event *)) kfree; } + old_fb = crtc->fb; ret = crtc->funcs->page_flip(crtc, fb, e); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { @@ -3759,9 +3773,18 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); kfree(e); } + /* Keep the old fb, don't unref it. */ + old_fb = NULL; + } else { + /* Unref only the old framebuffer. */ + fb = NULL; } out: + if (fb) + drm_framebuffer_unreference(fb); + if (old_fb) + drm_framebuffer_unreference(old_fb); drm_modeset_unlock_all(dev); return ret; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 14/37] drm: only take the crtc lock for ->cursor_set
First convert ->cursor_set to only take the crtc lock, since that seems to be the function with the least amount of state - the core ioctl function doesn't check anything which can change at runtime, so we don't have any object lifetime issues to contend. The only thing which is important is that the driver's implementation doesn't touch any state outside of that single crtc which is not yet properly protected by other locking: - ast: access the global ast->cache_kmap. Luckily we only have on crtc on this driver, so this is fine. Add a comment. - gma500: calls gma_power_begin|and and psb_gtt_pin|unpin, both which have their own locking to protect their state. Everything else is crtc-local. - i915: touches a bit of global gem state, all protected by the One Lock to Rule Them All (dev->struct_mutex). - nouveau: Pre-nv50 is all nice, nv50+ uses the evo channels to queue up all display changes. And some of these channels are device global. But this is fine now since the previous patch introduced an evo channel mutex. - radeon: Uses some indirect register access for cursor updates, but with the previous patches to protect these indirect 2-register access patterns with a spinlock, this should be fine now, too. - vmwgfx: I have no idea how that works - update_cursor_position doesn't take any per-crtc argument and I haven't figured out any other place where this could be set in some form of a side-channel. But vmwgfx definitely has more than one crtc (or at least can register more than one), so I have no idea how this is supposed to not fail with the current code already. Hence take the easy way out and simply acquire all locks (which requires dropping the crtc lock the core acquired for us). That way it's not worse off for consistency than the old code. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_drv.h |2 ++ drivers/gpu/drm/drm_crtc.c |6 -- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 32 ++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 5ccf984..5284292 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -98,6 +98,8 @@ struct ast_private { struct drm_gem_object *cursor_cache; uint64_t cursor_cache_gpu_addr; + /* Acces to this cache is protected by the crtc->mutex of the only crtc +* we have. */ struct ttm_bo_kmap_obj cache_kmap; int next_cursor; }; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 91e8068..62b5002 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2023,7 +2023,6 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) return -EINVAL; - drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); @@ -2038,20 +2037,23 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, goto out; } /* Turns off the cursor if handle is 0 */ + mutex_lock(&crtc->mutex); ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); + mutex_unlock(&crtc->mutex); } if (req->flags & DRM_MODE_CURSOR_MOVE) { if (crtc->funcs->cursor_move) { + drm_modeset_lock_all(dev); ret = crtc->funcs->cursor_move(crtc, req->x, req->y); + drm_modeset_unlock_all(dev); } else { ret = -EFAULT; goto out; } } out: - drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5474394..74b6734 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -180,16 +180,29 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, struct vmw_dma_buffer *dmabuf = NULL; int ret; + /* +* FIXME: Unclear whether there's any global state touched by the +* cursor_set function, especially vmw_cursor_update_position looks +* suspicious. For now take the easy route and reacquire all locks. We +* can do this since the caller in the drm core doesn't check anything +* which is protected by any looks. +*/ + mutex_unlock(&crtc->mutex); + drm_modeset_lock_all(dev_priv->dev); + /* A lot of the code assumes this */ - if (handle && (width != 64 || height != 64)) - return -EINVAL; + if (handle && (width != 64 || height
[Intel-gfx] [PATCH 35/37] drm/radeon: fix fence locking in the pageflip callback
We need to hold bdev->fence_lock while grabbing a reference to the fence, to prevent concurrent clearing/changing of the ttm_bo->sync_obj field. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/radeon_display.c |4 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 8724196..069d5cc 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -378,8 +378,12 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, work->old_rbo = rbo; obj = new_radeon_fb->obj; rbo = gem_to_radeon_bo(obj); + + spin_lock(&rbo->tbo.bdev->fence_lock); if (rbo->tbo.sync_obj) work->fence = radeon_fence_ref(rbo->tbo.sync_obj); + spin_unlock(&rbo->tbo.bdev->fence_lock); + INIT_WORK(&work->work, radeon_unpin_work_func); /* We borrow the event spin lock for protecting unpin_work */ -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 16/37] drm/: reorder framebuffer init sequence
With more fine-grained locking we can no longer rely on the big mode_config lock to prevent concurrent access to mode resources like framebuffers. Instead a framebuffer becomes accessible to other threads as soon as it is added to the relevant lookup structures. Hence it needs to be fully set up by the time drivers call drm_framebuffer_init. This patch here is the drivers part of that reorg. Nothing really fancy going on safe for three special cases. - exynos needs to be careful to properly unref all handles. - nouveau gets a resource leak fixed for free: one of the error cases didn't cleanup the framebuffer, which is now moot since the framebuffer is only registered once it is fully set up. - vmwgfx requires a slight reordering of operations, I'm hoping I didn't break anything (but it's refcount management only, so should be safe). Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_main.c|4 ++-- drivers/gpu/drm/cirrus/cirrus_main.c |9 +++-- drivers/gpu/drm/drm_fb_cma_helper.c | 10 +- drivers/gpu/drm/exynos/exynos_drm_fb.c| 20 +++- drivers/gpu/drm/gma500/framebuffer.c |4 ++-- drivers/gpu/drm/i915/intel_display.c |5 +++-- drivers/gpu/drm/mgag200/mgag200_main.c|8 +--- drivers/gpu/drm/nouveau/nouveau_display.c | 10 +- drivers/gpu/drm/radeon/radeon_display.c |2 +- drivers/gpu/drm/udl/udl_fb.c |2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 28 ++-- drivers/staging/omapdrm/omap_fb.c | 16 12 files changed, 64 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f668e6c..d5ba709 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -266,13 +266,13 @@ int ast_framebuffer_init(struct drm_device *dev, { int ret; + drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd); + ast_fb->obj = obj; ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); return ret; } - drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd); - ast_fb->obj = obj; return 0; } diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 6a9b12e..2eac87b 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -42,13 +42,13 @@ int cirrus_framebuffer_init(struct drm_device *dev, { int ret; + drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); + gfb->obj = obj; ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); if (ret) { DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); return ret; } - drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); - gfb->obj = obj; return 0; } @@ -79,6 +79,11 @@ cirrus_user_framebuffer_create(struct drm_device *dev, ret = cirrus_framebuffer_init(dev, cirrus_fb, mode_cmd, obj); if (ret) { + ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); + if (ret) { + DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); + return ret; + } drm_gem_object_unreference_unlocked(obj); kfree(cirrus_fb); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index fd9d0af..e1e0cb0 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -85,6 +85,11 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, if (!fb_cma) return ERR_PTR(-ENOMEM); + drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd); + + for (i = 0; i < num_planes; i++) + fb_cma->obj[i] = obj[i]; + ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); if (ret) { dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret); @@ -92,11 +97,6 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, return ERR_PTR(ret); } - drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd); - - for (i = 0; i < num_planes; i++) - fb_cma->obj[i] = obj[i]; - return fb_cma; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 4ef4cd3..179c177 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -136,15 +136,15 @@ exynos_drm_framebuffer_init(struct drm_device *dev, return ERR_PTR(-ENOMEM); } + drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); + exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); + ret
[Intel-gfx] [PATCH 11/37] drm/radeon: add W|RREG32_IDX for MM_INDEX|DATA based mmio accesss
Just refactoring to make the next patche simpler. Now all indirect register access in the new modesetting driver should go through the r100_mm_(w|r)reg fucntions. RADEON_READ_MM from the old driver seems to be totally unused, so just kill it. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/r100.c | 10 ++ drivers/gpu/drm/radeon/radeon.h | 16 ++-- drivers/gpu/drm/radeon/radeon_combios.c |6 ++ drivers/gpu/drm/radeon/radeon_cp.c | 14 -- drivers/gpu/drm/radeon/radeon_cursor.c | 17 + drivers/gpu/drm/radeon/radeon_drv.h |1 - 6 files changed, 27 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 376884f..ae4c857 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -4135,9 +4135,10 @@ int r100_init(struct radeon_device *rdev) return 0; } -uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) +uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, + bool always_indirect) { - if (reg < rdev->rmmio_size) + if (reg < rdev->rmmio_size && !always_indirect) return readl(((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); @@ -4145,9 +4146,10 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) } } -void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, + bool always_indirect) { - if (reg < rdev->rmmio_size) + if (reg < rdev->rmmio_size && !always_indirect) writel(v, ((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8c42d54..bcb00b8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1614,8 +1614,10 @@ int radeon_device_init(struct radeon_device *rdev, void radeon_device_fini(struct radeon_device *rdev); int radeon_gpu_wait_for_idle(struct radeon_device *rdev); -uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); -void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, + bool always_indirect); +void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, + bool always_indirect); u32 r100_io_rreg(struct radeon_device *rdev, u32 reg); void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); @@ -1631,9 +1633,11 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); #define WREG8(reg, v) writeb(v, (rdev->rmmio) + (reg)) #define RREG16(reg) readw((rdev->rmmio) + (reg)) #define WREG16(reg, v) writew(v, (rdev->rmmio) + (reg)) -#define RREG32(reg) r100_mm_rreg(rdev, (reg)) -#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg))) -#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v)) +#define RREG32(reg) r100_mm_rreg(rdev, (reg), false) +#define RREG32_IDX(reg) r100_mm_rreg(rdev, (reg), true) +#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg), false)) +#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v), false) +#define WREG32_IDX(reg, v) r100_mm_wreg(rdev, (reg), (v), true) #define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) #define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) #define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg)) @@ -1658,7 +1662,7 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); tmp_ |= ((val) & ~(mask)); \ WREG32_PLL(reg, tmp_); \ } while (0) -#define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg))) +#define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg), false)) #define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 45b660b..4af8912 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3246,11 +3246,9 @@ static uint32_t combios_detect_ram(struct drm_device *dev, int ram, while (ram--) { addr = ram * 1024 * 1024; /* write to each page */ - WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); - WREG32(RADEON_MM_DATA, 0xdeadbeef); + WREG32_IDX((addr) | RADEON_MM_APER, 0xdeadbeef); /* read back and verify */ - WREG32(RAD
[Intel-gfx] [PATCH 20/37] drm: revamp framebuffer cleanup interfaces
We have two classes of framebuffer - Created by the driver (atm only for fbdev), and the driver holds onto the last reference count until destruction. - Created by userspace and associated with a given fd. These framebuffers will be reaped when their assoiciated fb is closed. Now these two cases are set up differently, the framebuffers are on different lists and hence destruction needs to clean up different things. Also, for userspace framebuffers we remove them from any current usage, whereas for internal framebuffers it is assumed that the driver has done this already. Long story short, we need two different ways to cleanup such drivers. Three functions are involved in total: - drm_framebuffer_remove: Convenience function which removes the fb from all active usage and then drops the passed-in reference. - drm_framebuffer_unregister_private: Will remove driver-private framebuffers from relevant lists and drop the corresponding references. Should be called for driver-private framebuffers before dropping the last reference (or like for a lot of the drivers where the fbdev is embedded someplace else, before doing the cleanup manually). - drm_framebuffer_cleanup: Final cleanup for both classes of fbs, should be called by the driver's ->destroy callback once the last reference is gone. This patch just rolls out the new interfaces and updates all drivers (by adding calls to drm_framebuffer_unregister_private at all the right places)- no functional changes yet. Follow-on patches will move drm core code around and update the lifetime management for framebuffers, so that we are no longer required to keep framebuffers alive by locking mode_config.mutex. I've also updated the kerneldoc already. vmwgfx seems to again be a bit special, at least I haven't figured out how the fbdev support in that driver works. It smells like it's external though. v2: The i915 driver creates another private framebuffer in the load-detect code. Adjust its cleanup code, too. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_fb.c |1 + drivers/gpu/drm/cirrus/cirrus_fbdev.c |1 + drivers/gpu/drm/drm_crtc.c| 31 ++--- drivers/gpu/drm/drm_fb_cma_helper.c |5 - drivers/gpu/drm/exynos/exynos_drm_fbdev.c |4 +++- drivers/gpu/drm/gma500/framebuffer.c |1 + drivers/gpu/drm/i915/intel_display.c |6 -- drivers/gpu/drm/i915/intel_fb.c |1 + drivers/gpu/drm/mgag200/mgag200_fb.c |1 + drivers/gpu/drm/nouveau/nouveau_fbcon.c |1 + drivers/gpu/drm/radeon/radeon_fb.c|2 ++ drivers/gpu/drm/udl/udl_fb.c |1 + drivers/staging/omapdrm/omap_fbdev.c |8 ++-- include/drm/drm_crtc.h|1 + 14 files changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index d9ec779..3e6584b 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -290,6 +290,7 @@ static void ast_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&afbdev->helper); vfree(afbdev->sysram); + drm_framebuffer_unregister_private(&afb->base); drm_framebuffer_cleanup(&afb->base); } diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 6c6b4c8..3daea0f 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -258,6 +258,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, vfree(gfbdev->sysram); drm_fb_helper_fini(&gfbdev->helper); + drm_framebuffer_unregister_private(&gfb->base); drm_framebuffer_cleanup(&gfb->base); return 0; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 17cdd32..e2d70f6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -68,6 +68,7 @@ void drm_modeset_unlock_all(struct drm_device *dev) mutex_unlock(&dev->mode_config.mutex); } + EXPORT_SYMBOL(drm_modeset_unlock_all); /* Avoid boilerplate. I'm tired of typing. */ @@ -429,11 +430,34 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb) EXPORT_SYMBOL(drm_framebuffer_reference); /** + * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr + * @fb: fb to unregister + * + * Drivers need to call this when cleaning up driver-private framebuffers, e.g. + * those used for fbdev. Note that the caller must hold a reference of it's own, + * i.e. the object may not be destroyed through this call (since it'll lead to a + * locking inversion). + */ +void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) +{ +} +EXPORT_SYMBOL(drm_framebuffer_unregister_private); + +/** * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * - * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes - * it, s
[Intel-gfx] [PATCH 12/37] drm/radeon: make indirect register access concurrency-safe
With the new per-crtc locking mutliple set-cursor calls could happen in parallel. Out of sheer paranoia I've opted for an irqsave spinlock. But if there's indeed an access from interrupt contexts to these regs it's already broken with the old code, so this can likely just be reduced to a normal spinlock. Otoh the pageflip completion happens from the vblank irq handler ... Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/r100.c | 13 - drivers/gpu/drm/radeon/radeon.h|2 ++ drivers/gpu/drm/radeon/radeon_device.c |1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ae4c857..8ff7cac 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -4141,8 +4141,15 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, if (reg < rdev->rmmio_size && !always_indirect) return readl(((void __iomem *)rdev->rmmio) + reg); else { + unsigned long flags; + uint32_t ret; + + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); - return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); + + return ret; } } @@ -4152,8 +4159,12 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, if (reg < rdev->rmmio_size && !always_indirect) writel(v, ((void __iomem *)rdev->rmmio) + reg); else { + unsigned long flags; + + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); } } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bcb00b8..3dedb39 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1539,6 +1539,8 @@ struct radeon_device { /* Register mmio */ resource_size_t rmmio_base; resource_size_t rmmio_size; + /* protects concurrent MM_INDEX/DATA based register access */ + spinlock_t mmio_idx_lock; void __iomem*rmmio; radeon_rreg_t mc_rreg; radeon_wreg_t mc_wreg; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e2f5f88..49b0659 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1059,6 +1059,7 @@ int radeon_device_init(struct radeon_device *rdev, /* Registers mapping */ /* TODO: block userspace mapping of io register */ + spin_lock_init(&rdev->mmio_idx_lock); rdev->rmmio_base = pci_resource_start(rdev->pdev, 2); rdev->rmmio_size = pci_resource_len(rdev->pdev, 2); rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 33/37] drm/nouveau: try to protect nbo->pin_refcount
... by moving the bo_pin/bo_unpin manipulation of the pin_refcount under the protection of the ttm reservation lock. pin/unpin seems to get called from all over the place, so atm this is completely racy. After this patch there are only a few places in cleanup functions left which access ->pin_refcount without locking. But I'm hoping that those are safe and some other code invariant guarantees that this won't blow up. In any case, I only need to fix up pin/unpin to make ->pageflip work safely, so let's keep it at that. Add a comment to the header to explain the new locking rule. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/nouveau/nouveau_bo.c | 22 +++--- drivers/gpu/drm/nouveau/nouveau_bo.h |2 ++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4c950b4..2aa4745 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -300,17 +300,18 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) struct ttm_buffer_object *bo = &nvbo->bo; int ret; + ret = ttm_bo_reserve(bo, false, false, false, 0); + if (ret) + goto out; + if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo, 1 << bo->mem.mem_type, memtype); - return -EINVAL; + ret = -EINVAL; + goto out; } if (nvbo->pin_refcnt++) - return 0; - - ret = ttm_bo_reserve(bo, false, false, false, 0); - if (ret) goto out; nouveau_bo_placement_set(nvbo, memtype, 0); @@ -328,10 +329,8 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) break; } } - ttm_bo_unreserve(bo); out: - if (unlikely(ret)) - nvbo->pin_refcnt--; + ttm_bo_unreserve(bo); return ret; } @@ -342,13 +341,13 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) struct ttm_buffer_object *bo = &nvbo->bo; int ret; - if (--nvbo->pin_refcnt) - return 0; - ret = ttm_bo_reserve(bo, false, false, false, 0); if (ret) return ret; + if (--nvbo->pin_refcnt) + goto out; + nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); ret = nouveau_bo_validate(nvbo, false, false, false); @@ -365,6 +364,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) } } +out: ttm_bo_unreserve(bo); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index dec51b1..cd5631b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -28,6 +28,8 @@ struct nouveau_bo { struct nouveau_drm_tile *tile; struct drm_gem_object *gem; + + /* protect by the ttm reservation lock */ int pin_refcnt; struct ttm_bo_kmap_obj dma_buf_vmap; -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 26/37] drm: fb refcounting for dirtyfb_ioctl
We only need to ensure that the fb stays around for long enough. While at it, only grab the modeset locks when we need them (since most drivers don't implement the dirty callback, this should help jitter and stalls when using the generic modeset driver). Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 15 ++- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 28838cf..8132e13 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2561,14 +2561,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, r->fb_id); - if (!fb) { - ret = -EINVAL; - goto out_err1; - } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); + if (!fb) + return -EINVAL; num_clips = r->num_clips; clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; @@ -2606,17 +2601,19 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (fb->funcs->dirty) { + drm_modeset_lock_all(dev); ret = fb->funcs->dirty(fb, file_priv, flags, r->color, clips, num_clips); + drm_modeset_unlock_all(dev); } else { ret = -ENOSYS; - goto out_err2; } out_err2: kfree(clips); out_err1: - drm_modeset_unlock_all(dev); + drm_framebuffer_unreference(fb); + return ret; } -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 21/37] drm: reference framebuffers which are on the idr
Since otherwise looking and reference-counting around drm_framebuffer_lookup will be an unmanageable mess. With this change, an object can either be found in the idr and will stay around once we incremented the reference counter. Or it will be gone for good and can't be looked up using its id any more. Atomicity is guaranteed by the dev->mode_config.fb_lock. The newly-introduce fpriv->fbs_lock looks a bit redundant, but the next patch will shuffle the locking order between these two locks and all the modeset locks taken in modeset_lock_all, so we'll need it. Also, since userspace could do really funky stuff and race e.g. a getresources with an rmfb, we need to make sure that the kernel doesn't fall over trying to look-up an inexistent fb, or causing confusion by having two fbs around with the same id. Simply reset the framebuffer id to 0, which marks it as reaped. Any lookups of that id will fail, so the object is really gone for good from userspace's pov. Note that we still need to protect the "remove framebuffer from all use-cases" and the final unreference with the modeset-lock, since most framebuffer use-sites don't implement proper reference counting yet. We can only lift this once _all_ users are converted. With this change, two references are held on alife, but unused framebuffers: - The reference for the idr lookup, created in this patch. - For user-created framebuffers the fpriv->fbs reference, for driver-private fbs the driver is supposed to hold it's own last reference. Note that the dev->mode_config.fb_list itself does _not_ hold a reference onto the framebuffers (this list is essentially only used for debugfs files). Hence if there's anything left there when the driver has cleaned up all it's modeset resources, this is a ref-leak. WARN about it. Now we only need to fix up all other places to properly reference count framebuffers. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 118 ++-- 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e2d70f6..20ccdc4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -356,6 +356,9 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, if (ret) return ret; + /* Grab the idr reference. */ + drm_framebuffer_reference(fb); + dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); mutex_unlock(&dev->mode_config.fb_lock); @@ -371,6 +374,23 @@ static void drm_framebuffer_free(struct kref *kref) fb->funcs->destroy(fb); } +static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *obj = NULL; + struct drm_framebuffer *fb; + + mutex_lock(&dev->mode_config.idr_mutex); + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) + fb = NULL; + else + fb = obj_to_fb(obj); + mutex_unlock(&dev->mode_config.idr_mutex); + + return fb; +} + /** * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference * @dev: drm device @@ -383,22 +403,12 @@ static void drm_framebuffer_free(struct kref *kref) struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, uint32_t id) { - struct drm_mode_object *obj = NULL; struct drm_framebuffer *fb; mutex_lock(&dev->mode_config.fb_lock); - - mutex_lock(&dev->mode_config.idr_mutex); - obj = idr_find(&dev->mode_config.crtc_idr, id); - if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) - fb = NULL; - else - fb = obj_to_fb(obj); - mutex_unlock(&dev->mode_config.idr_mutex); - + fb = __drm_framebuffer_lookup(dev, id); if (fb) kref_get(&fb->refcount); - mutex_unlock(&dev->mode_config.fb_lock); return fb; @@ -429,6 +439,24 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_reference); +static void drm_framebuffer_free_bug(struct kref *kref) +{ + BUG(); +} + +/* dev->mode_config.fb_lock must be held! */ +static void __drm_framebuffer_unregister(struct drm_device *dev, +struct drm_framebuffer *fb) +{ + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.crtc_idr, fb->base.id); + mutex_unlock(&dev->mode_config.idr_mutex); + + fb->base.id = 0; + + kref_put(&fb->refcount, drm_framebuffer_free_bug); +} + /** * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr * @fb: fb to unregister @@ -440,6 +468,12 @@ EXPORT_SYMBOL(drm_framebuffe
[Intel-gfx] [PATCH 22/37] drm: nest modeset locks within fpriv->fbs_lock
Atm we still need to unconditionally take the modeset locks in the rmfb paths. But eventually we only want to take them if there are other users around as a slow-path. This way sane userspace avoids blocking on edid reads and other stuff in rmfb if it ensures that the fb isn't used anywhere by a crtc/plane. We can do a quick check for such other users once framebuffers are properly refcounting by locking at the refcount - if it's more than 1, there are other users left. Again, rmfb racing against other ioctls isn't a real problem, userspace is allowed to shoot its foot. This patch just prepares this by moving the modeset locks to nest within fpriv->fbs_lock. Now the distinction between the fbs_lock and the device-global fb_lock is clear, since we need to hold the fbs_lock outside of any modeset_locks in fb_release. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c |8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 20ccdc4..33e95bb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2266,13 +2266,13 @@ int drm_mode_addfb(struct drm_device *dev, drm_modeset_unlock_all(dev); return PTR_ERR(fb); } + drm_modeset_unlock_all(dev); mutex_lock(&file_priv->fbs_lock); or->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); mutex_unlock(&file_priv->fbs_lock); - drm_modeset_unlock_all(dev); return ret; } @@ -2449,6 +2449,7 @@ int drm_mode_addfb2(struct drm_device *dev, drm_modeset_unlock_all(dev); return PTR_ERR(fb); } + drm_modeset_unlock_all(dev); mutex_lock(&file_priv->fbs_lock); r->fb_id = fb->base.id; @@ -2456,7 +2457,6 @@ int drm_mode_addfb2(struct drm_device *dev, DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); mutex_unlock(&file_priv->fbs_lock); - drm_modeset_unlock_all(dev); return ret; } @@ -2651,7 +2651,6 @@ void drm_fb_release(struct drm_file *priv) struct drm_device *dev = priv->minor->dev; struct drm_framebuffer *fb, *tfb; - drm_modeset_lock_all(dev); mutex_lock(&priv->fbs_lock); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { @@ -2663,10 +2662,11 @@ void drm_fb_release(struct drm_file *priv) list_del_init(&fb->filp_head); /* This will also drop the fpriv->fbs reference. */ + drm_modeset_lock_all(dev); drm_framebuffer_remove(fb); + drm_modeset_unlock_all(dev); } mutex_unlock(&priv->fbs_lock); - drm_modeset_unlock_all(dev); } /** -- 1.7.10.4 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 28/37] drm: encapsulate crtc->set_config calls
With refcounting we need to adjust framebuffer refcounts at each callsite - much easier to do if they all call the same little helper function. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 19 +-- drivers/gpu/drm/drm_fb_helper.c|6 +++--- drivers/gpu/drm/i2c/ch7006_drv.c |2 +- drivers/gpu/drm/nouveau/nv04_display.c |2 +- drivers/gpu/drm/nouveau/nv17_tv.c |2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c|2 +- include/drm/drm_crtc.h |1 + 7 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ccf15ad..229853e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -536,7 +536,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) memset(&set, 0, sizeof(struct drm_mode_set)); set.crtc = crtc; set.fb = NULL; - ret = crtc->funcs->set_config(&set); + ret = drm_mode_set_config_internal(&set); if (ret) DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); } @@ -1974,6 +1974,21 @@ out: } /** + * drm_mode_set_config_internal - helper to call ->set_config + * @set: modeset config to set + * + * This is a little helper to wrap internal calls to the ->set_config driver + * interface. The only thing it adds is correct refcounting dance. + */ +int drm_mode_set_config_internal(struct drm_mode_set *set) +{ + struct drm_crtc *crtc = set->crtc; + + return crtc->funcs->set_config(set); +} +EXPORT_SYMBOL(drm_mode_set_config_internal); + +/** * drm_mode_setcrtc - set CRTC configuration * @dev: drm device for the ioctl * @data: data pointer for the ioctl @@ -2137,7 +2152,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = crtc->funcs->set_config(&set); + ret = drm_mode_set_config_internal(&set); out: kfree(connector_set); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d84ec67..403d53e 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -245,7 +245,7 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) int i, ret; for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; - ret = mode_set->crtc->funcs->set_config(mode_set); + ret = drm_mode_set_config_internal(mode_set); if (ret) error = true; } @@ -675,7 +675,7 @@ int drm_fb_helper_set_par(struct fb_info *info) drm_modeset_lock_all(dev); for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; - ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); + ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); if (ret) { drm_modeset_unlock_all(dev); return ret; @@ -711,7 +711,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - ret = crtc->funcs->set_config(modeset); + ret = drm_mode_set_config_internal(modeset); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 599099f..c5c947c 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -364,7 +364,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, .crtc = crtc, }; - crtc->funcs->set_config(&modeset); + drm_mode_set_config_internal(&modeset); } } diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 2cd6fb8..4c6e9f8 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -140,7 +140,7 @@ nv04_display_destroy(struct drm_device *dev) .crtc = crtc, }; - crtc->funcs->set_config(&modeset); + drm_mode_set_config_internal(&modeset); } /* Restore state */ diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 897b636..bb3abfc 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/
[Intel-gfx] [PATCH] tests/gem_seqno_wrap: dont sync when crossing half of seqno space
For seqno comparison to work they have to be less than UINT32_MAX/2 apart. So when crossing the half way of seqno space, be careful not to sync anything as this causes gpu hangs. Do real test with syncing only when we are about to wrap. --- tests/gem_seqno_wrap.c | 161 +++- 1 file changed, 117 insertions(+), 44 deletions(-) diff --git a/tests/gem_seqno_wrap.c b/tests/gem_seqno_wrap.c index b70f886..5ce8c93 100644 --- a/tests/gem_seqno_wrap.c +++ b/tests/gem_seqno_wrap.c @@ -47,7 +47,7 @@ #include "intel_gpu_tools.h" #include "rendercopy.h" -#define BUFFERS_TO_SYNC 128 +#define SAFETY_REGION 0x1f static int devid; static uint32_t last_seqno = 0; @@ -64,6 +64,8 @@ struct option_struct { int timeout; int dontwrap; int prewrap_space; + int random; + int buffers; }; static struct option_struct options; @@ -159,21 +161,34 @@ static void render_copyfunc(struct scratch_buf *src, } } -static int run_sync_test(void) +static void exchange_uint(void *array, unsigned i, unsigned j) +{ + unsigned *i_arr = array; + unsigned i_tmp; + + i_tmp = i_arr[i]; + i_arr[i] = i_arr[j]; + i_arr[j] = i_tmp; +} + +static int run_sync_test(int num_buffers, bool verify) { drm_intel_bufmgr *bufmgr; - int num_buffers = BUFFERS_TO_SYNC, max; + int max; drm_intel_bo *src[128], *dst1[128], *dst2[128]; int width = 128, height = 128; int fd; int i; int r = -1; int failed = 0; - + unsigned int *p_dst1, *p_dst2; struct scratch_buf s_src[128], s_dst[128]; fd = drm_open_any(); assert(fd >= 0); + + gem_quiescent_gpu(fd); + devid = intel_get_drm_devid(fd); max = gem_aperture_size (fd) / (1024 * 1024) / 2; @@ -187,7 +202,16 @@ static int run_sync_test(void) batch_3d = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd)); assert(batch_3d); + p_dst1 = malloc(num_buffers * sizeof(unsigned int)); + if (p_dst1 == NULL) + return -ENOMEM; + + p_dst2 = malloc(num_buffers * sizeof(unsigned int)); + if (p_dst2 == NULL) + return -ENOMEM; + for (i = 0; i < num_buffers; i++) { + p_dst1[i] = p_dst2[i] = i; src[i] = create_bo(bufmgr, i, width, height); dst1[i] = create_bo(bufmgr, ~i, width, height); dst2[i] = create_bo(bufmgr, ~i, width, height); @@ -195,19 +219,27 @@ static int run_sync_test(void) init_buffer(bufmgr, &s_dst[i], dst1[i], width, height); } - /* dummy = create_bo(bufmgr, 0, width, height); */ - - for (i = 0; i < num_buffers; i++) { - render_copyfunc(&s_src[i], &s_dst[i], width, height); - intel_copy_bo(batch_blt, dst2[i], dst1[i], width, height); - } - - for (i = 0; i < num_buffers; i++) { - r = cmp_bo(dst2[i], i, width, height); - if (r) { - printf("buffer %d differs, seqno_before_test 0x%x, approximated seqno on test fail 0x%x\n", - i, last_seqno_write, last_seqno_write + i * 2); - failed = -1; + drmtest_permute_array(p_dst1, num_buffers, exchange_uint); + drmtest_permute_array(p_dst2, num_buffers, exchange_uint); + + for (i = 0; i < num_buffers; i++) + render_copyfunc(&s_src[i], &s_dst[p_dst1[i]], width, height); + + /* Only sync between buffers if this is actual test run and +* not a seqno filler */ + if (verify) { + for (i = 0; i < num_buffers; i++) + intel_copy_bo(batch_blt, dst2[p_dst2[i]], dst1[p_dst1[i]], + width, height); + + for (i = 0; i < num_buffers; i++) { + r = cmp_bo(dst2[p_dst2[i]], i, width, height); + if (r) { + printf("buffer %d differs, seqno_before_test 0x%x, " + " approximated seqno on test fail 0x%x\n", + i, last_seqno_write, last_seqno_write + i * 2); + failed = -1; + } } } @@ -221,6 +253,11 @@ static int run_sync_test(void) intel_batchbuffer_free(batch_blt); drm_intel_bufmgr_destroy(bufmgr); + free(p_dst1); + free(p_dst2); + + gem_quiescent_gpu(fd); + close(fd); return failed; @@ -270,7 +307,9 @@ static int run_cmd(char *s) if (r == pid) { if(WIFEXITED(status)) { if (WEXITSTATUS(status)) - fprintf(stderr, "child returned with %d\n", WEXITSTATUS(status)); +
Re: [Intel-gfx] [PATCH 00/37] [RFC] revamped modeset locking
On Wed, Dec 12, 2012 at 02:06:40PM +0100, Daniel Vetter wrote: > Hi all, > > First thing first: It works, I now no longer have a few dropped frames every > 10s > on my testbox here with the pageflip i-g-t tests. > > Random notes: > > - New design has per-crtc locks to protect the crtc input-side (pageflip, > cursor) for r/w and the output state of the crtc (mode, dpms) as read-only. > It > also required completely revamped fb lifecycle management, those are now > refcounted for real (which is a nice cleanup). Imo the proposed rwsem hack > from Dave/Ajax is too ugly to life in comparison. > > - Smoke tested on i915, compile tested for x86 drivers, probably all arm > drivers > trivially broken. I plan add tons of i-g-t testscases to exercise all the > cornercases with i915 (so that lockdep has full coverage among other things) > and at least run radeon/nouveau a bit. I also need to set up an arm > crosscompiler. Generally testing feedback on !i915 highly welcome. > > - Driver audit: I've tried to not break anything more than it already is, and > for the big three desktop drivers fixup any related breakage I've noticed. > Big > unknown is vmwgfx since that driver is over my head. Generally review from > driver devs is required to check all corner-cases. > > - Merging, presuming people like this idea here: I think it'd be good to slurp > in the driver changes as early as possible. The big rework probably has to > go > in with a separate pull directly to drm-next for all drivers - there are > simply too many sync-points in this rework where all drivers need to follow > the new rules before core drm changes can be applied. > > - Having a global lock which synchronizing object destruction is a royal pain, > since it reliably results in that locking getting in the way almost > everywhere > when trying to implement refcounting. It's fixed now for fb & the > mode_config > mutex, but I'm already eagerly looking forward to simplifying > dev->struct_mutex > gem_bo cleanup rules. > > - drm teardown/setup synchronization and locking is terminally broken. Insane > volunteers welcome, I don't want to do this. > > - I've mentioned that reading too much driver code causes nightmares, right? > vmwgfx ... > > Please bring on the flames. I've forgotten to add: Patch series pushed out to the drm-kms-locking branch in my personal fdo repo: http://cgit.freedesktop.org/~danvet/drm/log/?h=drm-kms-locking -Daniel -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 34/37] drm/ttm: fix fence locking in ttm_buffer_object_transfer
On Wed, Dec 12, 2012 at 3:48 PM, Jerome Glisse wrote: > Instead of that i would just move the call to > ttm_buffer_object_transfer to happen before releasing the fence_lock > in ttm_bo_move_accel_cleanup , something like : Yeah, looks better. Fixed up locally. -Daniel -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] gfx context switch
Hi, all: When gfx executes batch buffer in render ring buffer, it will do context switch . Since only when the previous batch buffer has finished, the next batch buffer can start. the batch buffer is executed in order. So I think there is no need to do context switch. Why i915 driver introduce context switch ? If context switch is disabled, what error will occur ? Why gfx need context switch, can somebody give me a example to use context switch ? Thanks in advance. ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 00/81] drm/i915: Atomic mode setting / page flip, yet again
Another month, another massive atomic patchset. I managed to clean up warts left over from the modeset-rework rebase, but other than that I haven't really found the time to touch this too much since the last time I posted patches from this set. Seeing as my schedule isn't getting any less busy in the forseeable future, it would be nice to get this monster merged sooner rather than never. Ever since the code started to resemble something sane, I've tried to avoid squashing patches, just in case someone was actually trying to follow what's changed. But clearly some of the patches can be squashed, and that would probably allow some of the earlier ones to be dropped entirely. What's clearly needed is a test tool that will stresss the mode setting side of the code more. My glplane test just changes the modes in the beginning, and then just does flips and other plane stuff. I'll try to get something done on that front before Christmas. Repo is here: https://gitorious.org/vsyrjala/linux/commits/drm_atomic_23 The repo also contains 64bit get_user() implementation for x86-32, which I sent to lkml and x86 people for review. So this should now be testable even on a 32bit system. ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 01/81] drm: Add struct drm_region and assorted utility functions
From: Ville Syrjälä struct drm_region represents a two dimensional region. The utility functions are there to help driver writers. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 155 include/drm/drm_crtc.h | 24 +++ 2 files changed, 179 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d6d0072..f64e572 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3923,3 +3923,158 @@ int drm_format_vert_chroma_subsampling(uint32_t format) } } EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); + +/** + * drm_region_adjust_size - adjust the size of the region + * @r: region to be adjusted + * @x: horizontal adjustment + * @y: vertical adjustment + * + * Change the size of region @r by @x in the horizontal direction, + * and by @y in the vertical direction, while keeping the center + * of @r stationary. + * + * Positive @x and @y increase the size, negative values decrease it. + */ +void drm_region_adjust_size(struct drm_region *r, int x, int y) +{ + r->x1 -= x >> 1; + r->y1 -= y >> 1; + r->x2 += (x + 1) >> 1; + r->y2 += (y + 1) >> 1; +} +EXPORT_SYMBOL(drm_region_adjust_size); + +/** + * drm_region_translate - translate the region + * @r: region to be tranlated + * @x: horizontal translation + * @y: vertical translation + * + * Move region @r by @x in the horizontal direction, + * and by @y in the vertical direction. + */ +void drm_region_translate(struct drm_region *r, int x, int y) +{ + r->x1 += x; + r->y1 += y; + r->x2 += x; + r->y2 += y; +} +EXPORT_SYMBOL(drm_region_translate); + +/** + * drm_region_subsample - subsample a region + * @r: region to be subsampled + * @hsub: horizontal subsampling factor + * @vsub: vertical subsampling factor + * + * Divide the coordinates of region @r by @hsub and @vsub. + */ +void drm_region_subsample(struct drm_region *r, int hsub, int vsub) +{ + r->x1 /= hsub; + r->y1 /= vsub; + r->x2 /= hsub; + r->y2 /= vsub; +} +EXPORT_SYMBOL(drm_region_subsample); + +/** + * drm_region_width - determine the region width + * @r: region whose width is returned + * + * RETURNS: + * The width of the region. + */ +int drm_region_width(const struct drm_region *r) +{ + return r->x2 - r->x1; +} +EXPORT_SYMBOL(drm_region_width); + +/** + * drm_region_height - determine the region height + * @r: region whose height is returned + * + * RETURNS: + * The height of the region. + */ +int drm_region_height(const struct drm_region *r) +{ + return r->y2 - r->y1; +} +EXPORT_SYMBOL(drm_region_height); + +/** + * drm_region_visible - determine if the the region is visible + * @r: region whose visibility is returned + * + * RETURNS: + * @true if the region is visible, @false otherwise. + */ +bool drm_region_visible(const struct drm_region *r) +{ + return drm_region_width(r) > 0 && drm_region_height(r) > 0; +} +EXPORT_SYMBOL(drm_region_visible); + +/** + * drm_region_clip - clip one region by another region + * @r: region to be clipped + * @clip: clip region + * + * Clip region @r by region @clip. + * + * RETURNS: + * @true if the region is still visible after being clipped, + * @false otherwise. + */ +bool drm_region_clip(struct drm_region *r, const struct drm_region *clip) +{ + r->x1 = max(r->x1, clip->x1); + r->y1 = max(r->y1, clip->y1); + r->x2 = min(r->x2, clip->x2); + r->y2 = min(r->y2, clip->y2); + + return drm_region_visible(r); +} +EXPORT_SYMBOL(drm_region_clip); + +/** + * drm_region_clip_scaled - perform a scaled clip operation + * @src: source window region + * @dst: destination window region + * @clip: clip region + * @hscale: horizontal scaling factor + * @vscale: vertical scaling factor + * + * Clip region @dst by region @clip. Clip region @src by the same + * amounts multiplied by @hscale and @vscale. + * + * RETUTRNS: + * @true if region @dst is still visible after being clipped, + * @false otherwise + */ +bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, + const struct drm_region *clip, + int hscale, int vscale) +{ + int diff; + + diff = clip->x1 - dst->x1; + if (diff > 0) + src->x1 += diff * hscale; + diff = clip->y1 - dst->y1; + if (diff > 0) + src->y1 += diff * vscale; + diff = dst->x2 - clip->x2; + if (diff > 0) + src->x2 -= diff * hscale; + diff = dst->y2 - clip->y2; + if (diff > 0) + src->y2 -= diff * vscale; + + return drm_region_clip(dst, clip); +} +EXPORT_SYMBOL(drm_region_clip_scaled); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3538eda..0ac6d83 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1082,4 +1082,28 @@ extern int drm_format_plane_cpp(uint32_t format, int plane); ex
[Intel-gfx] [PATCH 02/81] drm: Add drm_calc_{hscale, vscale}() utility functions
From: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 102 include/drm/drm_crtc.h |4 ++ 2 files changed, 106 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f64e572..8918179 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4078,3 +4078,105 @@ bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, return drm_region_clip(dst, clip); } EXPORT_SYMBOL(drm_region_clip_scaled); + +/** + * drm_calc_hscale - calculate the horizontal scaling factor + * @src: source window region + * @dst: destination window region + * @min_hscale: minimum allowed horizontal scaling factor + * @max_hscale: maximum allowed horizontal scaling factor + * + * Calculate the horizontal scaling factor as + * (@src width) / (@dst width). + * + * If the calculated scaling factor is below @min_hscale, + * decrease the width of region @dst to compensate. + * + * If the calculcated scaling factor is above @max_hscale, + * decrease the width of region @src to compensate. + * + * RETURNS: + * The horizontal scaling factor. + */ +int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, + int min_hscale, int max_hscale) +{ + int src_w = drm_region_width(src); + int dst_w = drm_region_width(dst); + int hscale; + + if (dst_w <= 0) + return 0; + + hscale = src_w / dst_w; + + if (hscale < min_hscale) { + int max_dst_w = src_w / min_hscale; + + drm_region_adjust_size(dst, max_dst_w - dst_w, 0); + + return min_hscale; + } + + if (hscale > max_hscale) { + int max_src_w = dst_w * max_hscale; + + drm_region_adjust_size(src, max_src_w - src_w, 0); + + return max_hscale; + } + + return hscale; +} +EXPORT_SYMBOL(drm_calc_hscale); + +/** + * drm_calc_vscale - calculate the vertical scaling factor + * @src: source window region + * @dst: destination window region + * @min_vscale: minimum allowed vertical scaling factor + * @max_vscale: maximum allowed vertical scaling factor + * + * Calculate the vertical scaling factor as + * (@src height) / (@dst height). + * + * If the calculated scaling factor is below @min_vscale, + * decrease the height of region @dst to compensate. + * + * If the calculcated scaling factor is above @max_vscale, + * decrease the height of region @src to compensate. + * + * RETURNS: + * The vertical scaling factor. + */ +int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, + int min_vscale, int max_vscale) +{ + int src_h = drm_region_height(src); + int dst_h = drm_region_height(dst); + int vscale; + + if (dst_h <= 0) + return 0; + + vscale = src_h / dst_h; + + if (vscale < min_vscale) { + int max_dst_h = src_h / min_vscale; + + drm_region_adjust_size(dst, 0, max_dst_h - dst_h); + + return min_vscale; + } + + if (vscale > max_vscale) { + int max_src_h = dst_h * max_vscale; + + drm_region_adjust_size(src, 0, max_src_h - src_h); + + return max_vscale; + } + + return vscale; +} +EXPORT_SYMBOL(drm_calc_vscale); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0ac6d83..a80a346 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1105,5 +1105,9 @@ extern bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, const struct drm_region *clip, int hscale, int vscale); +extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, + int min_hscale, int max_hscale); +extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, + int min_vscale, int max_vscale); #endif /* __DRM_CRTC_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 03/81] drm: Keep a copy of last plane coordinates
From: Ville Syrjälä If the update_plane() operation succeeds, make a copy of the requested src and crtc coordinates, so that the the plane may be reclipped if the display mode changed later. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c |8 include/drm/drm_crtc.h |4 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8918179..3164131 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1852,6 +1852,14 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!ret) { plane->crtc = crtc; plane->fb = fb; + plane->crtc_x = plane_req->crtc_x; + plane->crtc_y = plane_req->crtc_y; + plane->crtc_w = plane_req->crtc_w; + plane->crtc_h = plane_req->crtc_h; + plane->src_x = plane_req->src_x; + plane->src_y = plane_req->src_y; + plane->src_w = plane_req->src_w; + plane->src_h = plane_req->src_h; } out: diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a80a346..6b7d809 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -672,6 +672,10 @@ struct drm_plane { void *helper_private; struct drm_object_properties properties; + + uint32_t src_x, src_y, src_w, src_h; + int32_t crtc_x, crtc_y; + uint32_t crtc_w, crtc_h; }; /** -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 04/81] drm: Add restore_fbdev_mode() hook to drm_fb_helper
From: Ville Syrjälä Add an optional driver specific restore_fbdev_mode() hook to drm_fb_helper. If the driver doesn't provide the hook, drm_fb_helper_restore_fbdev_mode() is called directly as before. In this hook the driver can disable additional planes, cursors etc. that shouldn't be visible while fbdev is in control. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_fb_helper.c |5 - include/drm/drm_fb_helper.h |1 + 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 05e623a..6902097 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -265,7 +265,10 @@ static bool drm_fb_helper_force_kernel_mode(void) if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF) continue; - ret = drm_fb_helper_restore_fbdev_mode(helper); + if (helper->funcs->restore_fbdev_mode) + ret = helper->funcs->restore_fbdev_mode(helper); + else + ret = drm_fb_helper_restore_fbdev_mode(helper); if (ret) error = true; } diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 5120b01..7f76e9c 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -56,6 +56,7 @@ struct drm_fb_helper_funcs { int (*fb_probe)(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); + int (*restore_fbdev_mode)(struct drm_fb_helper *helper); }; struct drm_fb_helper_connector { -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 05/81] drm: Export drm_property_create_blob() and drm_property_destroy_blob()
From: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c |8 +--- include/drm/drm_crtc.h |4 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3164131..38b8ce3 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3112,8 +3112,8 @@ done: return ret; } -static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, - void *data) +struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, + void *data) { struct drm_property_blob *blob; int ret; @@ -3138,14 +3138,16 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev list_add_tail(&blob->head, &dev->mode_config.property_blob_list); return blob; } +EXPORT_SYMBOL(drm_property_create_blob); -static void drm_property_destroy_blob(struct drm_device *dev, +void drm_property_destroy_blob(struct drm_device *dev, struct drm_property_blob *blob) { drm_mode_object_put(dev, &blob->base); list_del(&blob->head); kfree(blob); } +EXPORT_SYMBOL(drm_property_destroy_blob); int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 6b7d809..27812e0 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -970,6 +970,10 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags const char *name, uint64_t min, uint64_t max); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); +extern struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, + int length, void *data); +extern void drm_property_destroy_blob(struct drm_device *dev, + struct drm_property_blob *blob); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 06/81] drm: Allow signed values for range properties
From: Ville Syrjälä Treat a range property as signed when the unsigned minimum value is larger than the unsigned maximum value. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 17 ++--- 1 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 38b8ce3..7badd2a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3213,14 +3213,25 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_update_edid_property); -static bool drm_property_change_is_valid(struct drm_property *property, +static bool range_property_is_signed(const struct drm_property *property) +{ + return property->values[0] > property->values[1]; +} + +static bool drm_property_change_is_valid(const struct drm_property *property, uint64_t value) { if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; if (property->flags & DRM_MODE_PROP_RANGE) { - if (value < property->values[0] || value > property->values[1]) - return false; + if (range_property_is_signed(property)) { + if ((int64_t)value < (int64_t)property->values[0] || + (int64_t)value > (int64_t)property->values[1]) + return false; + } else { + if (value < property->values[0] || value > property->values[1]) + return false; + } return true; } else if (property->flags & DRM_MODE_PROP_BITMASK) { int i; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 07/81] drm: Allow drm_mode_object_find() to look up an object of any type
From: Ville Syrjälä To avoid having to pass object types from userspace for atomic mode setting ioctl, allow drm_mode_object_find() to look up an object of any type. This will only work as long as the all object types share the ID space. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c |3 ++- include/drm/drm_crtc.h |1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7badd2a..2dd3649 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -267,7 +267,8 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, mutex_lock(&dev->mode_config.idr_mutex); obj = idr_find(&dev->mode_config.crtc_idr, id); - if (!obj || (obj->type != type) || (obj->id != id)) + if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) || + (obj->id != id)) obj = NULL; mutex_unlock(&dev->mode_config.idr_mutex); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 27812e0..28a972a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -48,6 +48,7 @@ struct drm_object_properties; #define DRM_MODE_OBJECT_FB 0xfbfbfbfb #define DRM_MODE_OBJECT_BLOB 0x #define DRM_MODE_OBJECT_PLANE 0x +#define DRM_MODE_OBJECT_ANY 0 struct drm_mode_object { uint32_t id; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 08/81] drm: Export drm_encoder_crtc_ok
From: Ville Syrjälä --- drivers/gpu/drm/drm_crtc_helper.c |5 +++-- include/drm/drm_crtc_helper.h |3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7b2d378..0d62c94 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -312,8 +312,8 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions); * * Return false if @encoder can't be driven by @crtc, true otherwise. */ -static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, - struct drm_crtc *crtc) +bool drm_encoder_crtc_ok(struct drm_encoder *encoder, +struct drm_crtc *crtc) { struct drm_device *dev; struct drm_crtc *tmp; @@ -333,6 +333,7 @@ static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, return true; return false; } +EXPORT_SYMBOL(drm_encoder_crtc_ok); /* * Check the CRTC we're going to map each output to vs. its current diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index f43d556..5abae74 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -169,4 +169,7 @@ extern void drm_kms_helper_hotplug_event(struct drm_device *dev); extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev); +extern bool drm_encoder_crtc_ok(struct drm_encoder *encoder, + struct drm_crtc *crtc); + #endif -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 09/81] drm: Export drm_crtc_prepare_encoders()
From: Ville Syrjälä --- drivers/gpu/drm/drm_crtc_helper.c |3 ++- include/drm/drm_crtc_helper.h |1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 0d62c94..30eb557 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -340,7 +340,7 @@ EXPORT_SYMBOL(drm_encoder_crtc_ok); * CRTC. If they don't match, we have to disable the output and the CRTC * since the driver will have to re-route things. */ -static void +void drm_crtc_prepare_encoders(struct drm_device *dev) { struct drm_encoder_helper_funcs *encoder_funcs; @@ -357,6 +357,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev) drm_encoder_disable(encoder); } } +EXPORT_SYMBOL(drm_crtc_prepare_encoders); /** * drm_crtc_helper_set_mode - internal helper to set a mode diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 5abae74..7702a3a 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -171,5 +171,6 @@ extern void drm_kms_helper_poll_enable(struct drm_device *dev); extern bool drm_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc); +extern void drm_crtc_prepare_encoders(struct drm_device *dev); #endif -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 10/81] drm: Refactor object property check code
From: Ville Syrjälä Refactor the code to check whether an object has a specific property to a new function. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 20 ++-- 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2dd3649..0a9a7cb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3374,6 +3374,19 @@ out: return ret; } +static bool object_has_prop(const struct drm_mode_object *obj, u32 prop_id) +{ + int i; + + if (!obj->properties) + return false; + + for (i = 0; i < obj->properties->count; i++) + if (obj->properties->ids[i] == prop_id) + return true; + return false; +} + int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3382,7 +3395,6 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_mode_object *prop_obj; struct drm_property *property; int ret = -EINVAL; - int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -3395,11 +3407,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, if (!arg_obj->properties) goto out; - for (i = 0; i < arg_obj->properties->count; i++) - if (arg_obj->properties->ids[i] == arg->prop_id) - break; - - if (i == arg_obj->properties->count) + if (!object_has_prop(arg_obj, arg->prop_id)) goto out; prop_obj = drm_mode_object_find(dev, arg->prop_id, -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 11/81] drm: Export mode<->umode conversion functions
From: Ville Syrjälä Export drm_crtc_convert_to_umode() and drm_crtc_convert_umode(). Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 10 ++ include/drm/drm_crtc.h |4 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0a9a7cb..3709f8c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1119,8 +1119,8 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to * the user. */ -static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, - const struct drm_display_mode *in) +void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, + const struct drm_display_mode *in) { WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || @@ -1146,6 +1146,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } +EXPORT_SYMBOL(drm_crtc_convert_to_umode); /** * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode @@ -1161,8 +1162,8 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, * RETURNS: * Zero on success, errno on failure. */ -static int drm_crtc_convert_umode(struct drm_display_mode *out, - const struct drm_mode_modeinfo *in) +int drm_crtc_convert_umode(struct drm_display_mode *out, + const struct drm_mode_modeinfo *in) { if (in->clock > INT_MAX || in->vrefresh > INT_MAX) return -ERANGE; @@ -1186,6 +1187,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, return 0; } +EXPORT_SYMBOL(drm_crtc_convert_umode); /** * drm_mode_getresources - get graphics configuration diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 28a972a..23f2f37 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1090,6 +1090,10 @@ extern int drm_format_num_planes(uint32_t format); extern int drm_format_plane_cpp(uint32_t format, int plane); extern int drm_format_horz_chroma_subsampling(uint32_t format); extern int drm_format_vert_chroma_subsampling(uint32_t format); +extern void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, + const struct drm_display_mode *in); +extern int drm_crtc_convert_umode(struct drm_display_mode *out, + const struct drm_mode_modeinfo *in); /** * drm_region - two dimensional region -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 12/81] drm: Make blobs resizeable
From: Ville Syrjälä When first allocated blobs can be given a maximum size for which memory is allocated. Later the data inside the blob can be replaced, assuming that the maximum size is not exceeded. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 45 ++- include/drm/drm_crtc.h |8 ++- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3709f8c..aeda9f4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2926,6 +2926,9 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) { struct drm_property_enum *prop_enum, *pt; + if (!property) + return; + list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { list_del(&prop_enum->head); kfree(prop_enum); @@ -3115,16 +3118,24 @@ done: return ret; } -struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, - void *data) +struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, + unsigned int length, + unsigned int max_length, + const void *data) { struct drm_property_blob *blob; int ret; - if (!length || !data) + if (!!length != !!data) return NULL; - blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); + if (max_length < length) + max_length = length; + + if (max_length == 0) + return NULL; + + blob = kzalloc(sizeof(struct drm_property_blob)+max_length, GFP_KERNEL); if (!blob) return NULL; @@ -3134,18 +3145,40 @@ struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int l return NULL; } + blob->max_length = max_length; blob->length = length; - memcpy(blob->data, data, length); + if (length) + memcpy(blob->data, data, length); list_add_tail(&blob->head, &dev->mode_config.property_blob_list); return blob; } EXPORT_SYMBOL(drm_property_create_blob); +int drm_property_blob_replace_data(struct drm_property_blob *blob, + unsigned int length, const void *data) +{ + if (!!length != !!data) + return -EINVAL; + + if (length > blob->max_length) + return -ENOSPC; + + blob->length = length; + if (length) + memcpy(blob->data, data, length); + + return 0; +} +EXPORT_SYMBOL(drm_property_blob_replace_data); + void drm_property_destroy_blob(struct drm_device *dev, struct drm_property_blob *blob) { + if (!blob) + return; + drm_mode_object_put(dev, &blob->base); list_del(&blob->head); kfree(blob); @@ -3204,7 +3237,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, size = EDID_LENGTH * (1 + edid->extensions); connector->edid_blob_ptr = drm_property_create_blob(connector->dev, - size, edid); + size, 0, edid); if (!connector->edid_blob_ptr) return -EINVAL; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 23f2f37..5b8b1b7 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -276,6 +276,7 @@ struct drm_property_blob { struct drm_mode_object base; struct list_head head; unsigned int length; + unsigned int max_length; unsigned char data[]; }; @@ -972,7 +973,12 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags uint64_t min, uint64_t max); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, - int length, void *data); + unsigned int level, + unsigned int max_length, + const void *data); +extern int drm_property_blob_replace_data(struct drm_property_blob *blob, + unsigned int length, + const void *data); extern void drm_property_destroy_blob(struct drm_device *dev, struct drm_property_blob *blob); extern int drm_property_add_enum(stru
[Intel-gfx] [PATCH 13/81] drm: Add drm_flip helper
From: Ville Syrjälä The drm_flip mechanism can be used to implement robust page flipping support, and also to synchronize the flips on multiple hardware scanout engines (eg. CRTCs and overlays). Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/Makefile |2 +- drivers/gpu/drm/drm_flip.c | 376 include/drm/drm_flip.h | 244 3 files changed, 621 insertions(+), 1 deletions(-) create mode 100644 drivers/gpu/drm/drm_flip.c create mode 100644 include/drm/drm_flip.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 6f58c81..f2965de 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -12,7 +12,7 @@ drm-y :=drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_crtc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ - drm_trace_points.o drm_global.o drm_prime.o + drm_trace_points.o drm_global.o drm_prime.o drm_flip.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_flip.c b/drivers/gpu/drm/drm_flip.c new file mode 100644 index 000..6ccc3f8 --- /dev/null +++ b/drivers/gpu/drm/drm_flip.c @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Ville Syrjälä + */ + +#include + +static void drm_flip_driver_cleanup(struct work_struct *work) +{ + struct drm_flip *flip, *next; + struct drm_flip_driver *driver = + container_of(work, struct drm_flip_driver, cleanup_work); + LIST_HEAD(list); + + spin_lock_irq(&driver->lock); + + list_cut_position(&list, + &driver->cleanup_list, + driver->cleanup_list.prev); + + spin_unlock_irq(&driver->lock); + + if (list_empty(&list)) + return; + + list_for_each_entry_safe(flip, next, &list, list) { + struct drm_flip_helper *helper = flip->helper; + + WARN_ON(!flip->finished); + + helper->funcs->cleanup(flip); + } +} + +static void drm_flip_driver_finish(struct work_struct *work) +{ + struct drm_flip *flip, *next; + struct drm_flip_driver *driver = + container_of(work, struct drm_flip_driver, finish_work); + LIST_HEAD(list); + bool need_cleanup = false; + + spin_lock_irq(&driver->lock); + + list_cut_position(&list, + &driver->finish_list, + driver->finish_list.prev); + + spin_unlock_irq(&driver->lock); + + if (list_empty(&list)) + return; + + list_for_each_entry_safe(flip, next, &list, list) { + struct drm_flip_helper *helper = flip->helper; + + helper->funcs->finish(flip); + + spin_lock_irq(&driver->lock); + + flip->finished = true; + + /* +* It's possible that drm_flip_set_scanout() was called after we +* pulled this flip from finish_list, in which case the flip +* could be in need of cleanup, but not on cleanup_list. +*/ + if (flip == helper->scanout_flip) { + list_del_init(&flip->list); + } else { + need_cleanup = true; + list_move_tail(&flip->list, &driver->cleanup_list); + } + + spin_unlock_irq(&driver->lock); + } + + if (need_cleanup) + queue_work(driver->wq, &driver->cleanup_work); +} + +static bool drm_flip_set_scanout(struct drm_flip_helper *helper, +struct drm_fl
[Intel-gfx] [PATCH 15/81] drm: Add the atomic modeset ioctl
From: Ville Syrjälä This new ioctl can be used to update an arbitrary set of object properties in one operation. The ioctl simply takes a list of object IDs and property IDs and their values. For setting values of blob properties, the property value indicates the length of the data, and the actual data is passed via another blob pointer. Three flags are currently supported to alter the behaviour of the ioctl: - DRM_MODE_ATOMIC_TEST_ONLY indicates that the new state chould only be checked for validity, but not hardware state is to be modified. - DRM_MODE_ATOMIC_EVENT requests that asynchronous completion events be sent back to user space. A new event type is added for this purpose. - DRM_MODE_ATOMIC_NONBLOCK indicates that the operation must be completed asynchronously without blocking the the caller for significant amounts of time. Internally the driver must implement the functions pointers in struct drm_atomic_funcs to support the new ioctl. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 146 +++ drivers/gpu/drm/drm_drv.c |1 + include/drm/drmP.h |8 +++ include/drm/drm_crtc.h | 13 include/uapi/drm/drm.h | 12 include/uapi/drm/drm_mode.h | 17 + 6 files changed, 197 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index aeda9f4..897ff46 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4245,3 +4245,149 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, return vscale; } EXPORT_SYMBOL(drm_calc_vscale); + +int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_atomic *arg = data; + uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); + uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); + uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); + uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); + uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr); + unsigned int copied_objs = 0; + unsigned int copied_props = 0; + unsigned int copied_blobs = 0; + void *state; + int ret = 0; + unsigned int i, j; + + if (!dev->driver->atomic_funcs || + !dev->driver->atomic_funcs->begin || + !dev->driver->atomic_funcs->set || + !dev->driver->atomic_funcs->check || + !dev->driver->atomic_funcs->commit || + !dev->driver->atomic_funcs->end) + return -ENOSYS; + + if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK)) + return -EINVAL; + + /* can't test and expect an event at the same time. */ + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY && arg->flags & DRM_MODE_ATOMIC_EVENT) + return -EINVAL; + + mutex_lock(&dev->mode_config.mutex); + + state = dev->driver->atomic_funcs->begin(dev, file_priv, arg->flags, arg->user_data); + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto unlock; + } + + for (i = 0; i < arg->count_objs; i++) { + uint32_t obj_id, count_props; + struct drm_mode_object *obj; + + if (get_user(obj_id, objs_ptr + copied_objs)) { + ret = -EFAULT; + goto out; + } + + obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); + if (!obj || !obj->properties) { + ret = -ENOENT; + goto out; + } + + if (get_user(count_props, count_props_ptr + copied_objs)) { + ret = -EFAULT; + goto out; + } + + copied_objs++; + + for (j = 0; j < count_props; j++) { + uint32_t prop_id; + uint64_t prop_value; + struct drm_mode_object *prop_obj; + struct drm_property *prop; + void *blob_data = NULL; + + if (get_user(prop_id, props_ptr + copied_props)) { + ret = -EFAULT; + goto out; + } + + if (!object_has_prop(obj, prop_id)) { + ret = -EINVAL; + goto out; + } + + prop_obj = drm_mode_object_find(dev, prop_id, DRM_MODE_OBJECT_PROPERTY); + if (!prop_obj) { + ret = -ENOENT; + goto
[Intel-gfx] [PATCH 14/81] drm: Add mode_blob and connector_ids_blob to drm_crtc
From: Ville Syrjälä These will be ued by standard properties MODE and CONNECTOR_IDS. Signed-off-by: Ville Syrjälä --- include/drm/drm_crtc.h |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5b8b1b7..d05d302 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -423,6 +423,9 @@ struct drm_crtc { void *helper_private; struct drm_object_properties properties; + + struct drm_property_blob *mode_blob; + struct drm_property_blob *connector_ids_blob; }; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 16/81] drm/i915: Use drm_format_plane_cpp() rather than bits_per_pixel/8
From: Ville Syrjälä bits_per_pixel may not be populated for all pixel formats, so let's just use drm_format_plane_cpp(). Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 12 ++-- 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 21dd4db..a4e71e5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1991,6 +1991,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, unsigned long linear_offset; u32 dspcntr; u32 reg; + unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0); switch (plane) { case 0: @@ -2049,13 +2050,12 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, I915_WRITE(reg, dspcntr); - linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + linear_offset = y * fb->pitches[0] + x * cpp; if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = intel_gen4_compute_offset_xtiled(&x, &y, -fb->bits_per_pixel / 8, -fb->pitches[0]); +cpp, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; } else { intel_crtc->dspaddr_offset = linear_offset; @@ -2088,6 +2088,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, unsigned long linear_offset; u32 dspcntr; u32 reg; + unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0); switch (plane) { case 0: @@ -2144,11 +2145,10 @@ static int ironlake_update_plane(struct drm_crtc *crtc, I915_WRITE(reg, dspcntr); - linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + linear_offset = y * fb->pitches[0] + x * cpp; intel_crtc->dspaddr_offset = intel_gen4_compute_offset_xtiled(&x, &y, -fb->bits_per_pixel / 8, -fb->pitches[0]); +cpp, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 17/81] drm/i915: Implement proper clipping for video sprites
From: Ville Syrjälä Properly clip the source when the destination gets clipped by the pipe dimensions. Sadly the video sprite hardware is rather limited so it can't do proper sub-pixel postitioning. Resort to a best effort approach, where the source coordinates are rounded to the nearest (macro)pixel boundary. Also do some additional checking against various hardware limits. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_sprite.c | 171 +++ 1 files changed, 111 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 827dcd4..77ca0da 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -120,11 +120,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = intel_gen4_compute_offset_xtiled(&x, &y, -fb->bits_per_pixel / 8, -fb->pitches[0]); +pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET @@ -286,11 +285,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); - linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = intel_gen4_compute_offset_xtiled(&x, &y, -fb->bits_per_pixel / 8, -fb->pitches[0]); +pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; if (obj->tiling_mode != I915_TILING_NONE) @@ -409,6 +407,20 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) key->flags = I915_SET_COLORKEY_NONE; } +static bool +format_is_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YVYU: + return true; + default: + return false; + } +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -420,35 +432,68 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj, *old_obj; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct drm_i915_gem_object *old_obj = intel_plane->obj; int pipe = intel_plane->pipe; enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); int ret = 0; - int x = src_x >> 16, y = src_y >> 16; int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; bool disable_primary = false; - - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - old_obj = intel_plane->obj; - - src_w = src_w >> 16; - src_h = src_h >> 16; - - /* Pipe must be running... */ - if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) - return -EINVAL; - - if (crtc_x >= primary_w || crtc_y >= primary_h) - return -EINVAL; + bool visible; + int hscale, vscale; + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); + struct drm_region src = { + .x1 = src_x, + .x2 = src_x + src_w, + .y1 = src_y, + .y2 = src_y + src_h, + }; + struct drm_region dst = { + .x1 = crtc_x, + .x2 = crtc_x + crtc_w, + .y1 = crtc_y, + .y2 = crtc_y + crtc_h, + }; + const struct drm_region clip = { + .x2 = crtc->mode.hdisplay, + .y2 = crtc->mode.vdisplay, + }; /* Don't modify another pipe's plane */ if (intel_plane->pipe != intel_crtc->pipe) return -EINVAL; + if (fb->width < 3 || fb->height < 3 || fb->pitches[
[Intel-gfx] [PATCH 18/81] drm/i915: Implement restore_fbdev_mode hook
From: Ville Syrjälä Convert intel_fb_restore_mode to be useable as the drm_fb_helper.restore_fbdev_mode hook. This will cause all planes to be disabled when swithing back to fbcon. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_dma.c |2 +- drivers/gpu/drm/i915/intel_drv.h |2 +- drivers/gpu/drm/i915/intel_fb.c | 14 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6fec5d4..392c9a1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1790,7 +1790,7 @@ void i915_driver_lastclose(struct drm_device * dev) return; if (drm_core_check_feature(dev, DRIVER_MODESET)) { - intel_fb_restore_mode(dev); + intel_fb_restore_mode(&dev_priv->fbdev->helper); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6724be8..16770cb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -606,7 +606,7 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); -extern void intel_fb_restore_mode(struct drm_device *dev); +extern int intel_fb_restore_mode(struct drm_fb_helper *helper); extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b7773e5..3ab7967 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -195,6 +195,7 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .gamma_set = intel_crtc_fb_gamma_set, .gamma_get = intel_crtc_fb_gamma_get, .fb_probe = intel_fb_find_or_create_single, + .restore_fbdev_mode = intel_fb_restore_mode, }; static void intel_fbdev_destroy(struct drm_device *dev, @@ -275,22 +276,27 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } -void intel_fb_restore_mode(struct drm_device *dev) +int intel_fb_restore_mode(struct drm_fb_helper *helper) { + struct drm_device *dev = helper->dev; int ret; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; mutex_lock(&dev->mode_config.mutex); - ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); - if (ret) + ret = drm_fb_helper_restore_fbdev_mode(helper); + if (ret) { DRM_DEBUG("failed to restore crtc mode\n"); + goto out; + } /* Be sure to shut off any planes that may be active */ list_for_each_entry(plane, &config->plane_list, head) plane->funcs->disable_plane(plane); +out: mutex_unlock(&dev->mode_config.mutex); + + return ret; } -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 19/81] drm/i915: Split clipping and checking from update_plane hook
From: Ville Syrjälä Split the update_plane() codepath into two separate steps. The first step checkis and clips the plane, and the second step actually commits the changes to the hardware. This allows the atomic modesetting code to perform all checks before clobering hardware state. The update_plane() hook is reduced to a thin wrapper calling both check and commit functions. Buffer (un)pinning is still being performed in the commit step. This needs to be changed as well, so that the atomic modesetting code can try to pin all new buffers before touching the hardware. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_drv.h| 15 +- drivers/gpu/drm/i915/intel_sprite.c | 411 ++- 2 files changed, 266 insertions(+), 160 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 16770cb..0d7c2fc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -231,6 +231,15 @@ struct intel_crtc { uint32_t ddi_pll_sel; }; +struct intel_plane_coords { + /* disabled or fully clipped? */ + bool visible; + /* coordinates clipped against pipe dimensions */ + int32_t crtc_x, crtc_y; + uint32_t crtc_w, crtc_h; + uint32_t src_x, src_y, src_w, src_h; +}; + struct intel_plane { struct drm_plane base; enum pipe pipe; @@ -240,11 +249,7 @@ struct intel_plane { u32 lut_r[1024], lut_g[1024], lut_b[1024]; void (*update_plane)(struct drm_plane *plane, struct drm_framebuffer *fb, -struct drm_i915_gem_object *obj, -int crtc_x, int crtc_y, -unsigned int crtc_w, unsigned int crtc_h, -uint32_t x, uint32_t y, -uint32_t src_w, uint32_t src_h); +const struct intel_plane_coords *clip); void (*disable_plane)(struct drm_plane *plane); int (*update_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 77ca0da..d64cefd 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -36,16 +36,189 @@ #include #include "i915_drv.h" +static bool +format_is_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YVYU: + return true; + default: + return false; + } +} + +static void intel_clip_plane(const struct drm_plane *plane, +const struct drm_crtc *crtc, +const struct drm_framebuffer *fb, +struct intel_plane_coords *coords) +{ + const struct intel_plane *intel_plane = to_intel_plane(plane); + const struct drm_display_mode *mode = &crtc->mode; + int hscale, vscale; + struct drm_region src = { + .x1 = coords->src_x, + .x2 = coords->src_x + coords->src_w, + .y1 = coords->src_y, + .y2 = coords->src_y + coords->src_h, + }; + struct drm_region dst = { + .x1 = coords->crtc_x, + .x2 = coords->crtc_x + coords->crtc_w, + .y1 = coords->crtc_y, + .y2 = coords->crtc_y + coords->crtc_h, + }; + const struct drm_region clip = { + .x2 = mode->hdisplay, + .y2 = mode->vdisplay, + }; + + hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 16); + vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 16); + + coords->visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, vscale); + + coords->crtc_x = dst.x1; + coords->crtc_y = dst.y1; + coords->crtc_w = drm_region_width(&dst); + coords->crtc_h = drm_region_height(&dst); + + /* HW doesn't seem to like smaller sprite, even when scaling */ + /* FIXME return an error instead? */ + if (coords->crtc_w < 3 || coords->crtc_h < 3) + coords->visible = false; + + /* +* Hardware doesn't handle subpixel coordinates. +* Round to nearest (macro)pixel boundary. +*/ + if (format_is_yuv(fb->pixel_format)) { + coords->src_x = ((src.x1 + 0x1) >> 17) << 1; + coords->src_w = (((src.x2 + 0x1) >> 17) << 1) - coords->src_x; + } else { + coords->src_x = (src.x1 + 0x8000) >> 16; + coords->src_w = ((src.x2 + 0x8000) >> 16) - coords->src_x; + } + coords->src_y = (src.y1 + 0x8000) >> 16; + coords->src_h = ((src.y2 + 0x8000) >> 16) - coords->src_y; + + /* Account for minimum source size when scaling */
[Intel-gfx] [PATCH 20/81] drm/i915: Factor out i9xx_compute_clocks() like ironlake_compute_clocks()
From: Ville Syrjälä Split the clock stuff out. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 128 -- 1 files changed, 75 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a4e71e5..0fa9c2a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4544,6 +4544,76 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); } +static bool i9xx_compute_clocks(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, + bool *has_reduced_clock, + intel_clock_t *reduced_clock, + int *refclk, int *num_connectors, bool *is_dp) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + const intel_limit_t *limit; + bool ret, is_sdvo = false, is_tv = false, is_lvds = false; + + *num_connectors = 0; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (encoder->needs_tv_clock) + is_tv = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_DISPLAYPORT: + *is_dp = true; + break; + } + + (*num_connectors)++; + } + + *refclk = i9xx_get_refclk(crtc, *num_connectors); + + /* +* Returns a set of divisors for the desired target clock with the given +* refclk, or FALSE. The returned values represent the clock equation: +* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. +*/ + limit = intel_limit(crtc, *refclk); + ret = limit->find_pll(limit, crtc, adjusted_mode->clock, *refclk, NULL, + clock); + if (!ret) + return false; + + if (is_lvds && dev_priv->lvds_downclock_avail) { + /* +* Ensure we match the reduced clock's P to the target clock. +* If the clocks don't match, we can't switch the display clock +* by using the FP0/FP1. In such case we will disable the LVDS +* downclock feature. + */ + *has_reduced_clock = limit->find_pll(limit, crtc, +dev_priv->lvds_downclock, +*refclk, +clock, +reduced_clock); + } + + if (is_sdvo && is_tv) + i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); + + return true; +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4558,44 +4628,13 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dspcntr, pipeconf; - bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *encoder; - const intel_limit_t *limit; + bool ok, has_reduced_clock = false; + bool is_dp = false; int ret; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; - } - - num_connectors++; - } - - refclk = i9xx_get_refclk(crtc, num_connectors); - - /* -* Returns a set of divisors for the desired target clock with the given -* refclk, or FALSE. The returned values represent the
[Intel-gfx] [PATCH 21/81] drm/i915: Consitify adjusted_mode parameter
From: Ville Syrjälä i9xx_adjust_sdvo_tv_clock(), i9xx_compute_clocks() and ironlake_compute_clocks() do not modify the adjusted_mode passed in, so pass it as const. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0fa9c2a..2a2c664 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4159,7 +4159,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) return refclk; } -static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode, +static void i9xx_adjust_sdvo_tv_clock(const struct drm_display_mode *adjusted_mode, intel_clock_t *clock) { /* SDVO TV has fixed PLL values depend on its clock range, @@ -4545,7 +4545,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, } static bool i9xx_compute_clocks(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, + const struct drm_display_mode *adjusted_mode, intel_clock_t *clock, bool *has_reduced_clock, intel_clock_t *reduced_clock, @@ -5135,7 +5135,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, } static bool ironlake_compute_clocks(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, + const struct drm_display_mode *adjusted_mode, intel_clock_t *clock, bool *has_reduced_clock, intel_clock_t *reduced_clock) -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 23/81] drm/i915: store cursor_handle in struct intel_crtc
From: Ander Conselvan de Oliveira This way it is possible to check if the cursor changed without doing any setup. Will be useful for the atomic modesetting api. --- drivers/gpu/drm/i915/intel_display.c |1 + drivers/gpu/drm/i915/intel_drv.h |2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dcd61fb..2a32cb0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6260,6 +6260,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, mutex_unlock(&dev->struct_mutex); intel_crtc->cursor_addr = addr; + intel_crtc->cursor_handle = handle; intel_crtc->cursor_bo = obj; intel_crtc->cursor_width = width; intel_crtc->cursor_height = height; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0d7c2fc..e77202c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -220,7 +220,7 @@ struct intel_crtc { unsigned long dspaddr_offset; struct drm_i915_gem_object *cursor_bo; - uint32_t cursor_addr; + uint32_t cursor_addr, cursor_handle; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; bool cursor_visible; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 24/81] drm/i915: split cursor setting code into prepare/commit/unref parts
From: Ander Conselvan de Oliveira The atomic mode setting API will need to pin the cursor bo without making changes to the current setup. Only on a later stage the cursor registers can be written and the previous bo released. This patch splits intel_crtc_cursor_set() into three parts: prepare, commit and unref. intel_crtc_cursor_prepare() will pin the cursor bo and return a gem object and the address to be written to the cursor registers. intel_crtc_cursor_commit() takes that object and address and actually changes the cursor. intel_crtc_cursor_unref() is used to release the previous cursor bo. --- drivers/gpu/drm/i915/intel_display.c | 90 + 1 files changed, 68 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a32cb0..0f25a07 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6173,10 +6173,12 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, } } -static int intel_crtc_cursor_set(struct drm_crtc *crtc, +static int intel_crtc_cursor_prepare(struct drm_crtc *crtc, struct drm_file *file, uint32_t handle, -uint32_t width, uint32_t height) +uint32_t width, uint32_t height, +struct drm_i915_gem_object **obj_ret, +uint32_t *addr_ret) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -6188,10 +6190,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* if we want to turn off the cursor ignore width and height */ if (!handle) { DRM_DEBUG_KMS("cursor off\n"); - addr = 0; - obj = NULL; - mutex_lock(&dev->struct_mutex); - goto finish; + *addr_ret = 0; + *obj_ret = NULL; + return 0; } /* Currently we only support 64x64 cursors */ @@ -6247,17 +6248,46 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, if (IS_GEN2(dev)) I915_WRITE(CURSIZE, (height << 12) | width); - finish: - if (intel_crtc->cursor_bo) { - if (dev_priv->info->cursor_needs_physical) { - if (intel_crtc->cursor_bo != obj) - i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo); - } else - i915_gem_object_unpin(intel_crtc->cursor_bo); - drm_gem_object_unreference(&intel_crtc->cursor_bo->base); - } + mutex_unlock(&dev->struct_mutex); + + *obj_ret = obj; + *addr_ret = addr; + + return 0; +fail_unpin: + i915_gem_object_unpin(obj); +fail_locked: + mutex_unlock(&dev->struct_mutex); +fail: + drm_gem_object_unreference_unlocked(&obj->base); + return ret; +} + +static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc, + struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + mutex_lock(&dev->struct_mutex); + + if (dev_priv->info->cursor_needs_physical) { + if (obj != intel_crtc->cursor_bo) + i915_gem_detach_phys_object(dev, obj); + } else + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); +} + +static void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, +uint32_t width, uint32_t height, +struct drm_i915_gem_object *obj, +uint32_t addr) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); intel_crtc->cursor_addr = addr; intel_crtc->cursor_handle = handle; @@ -6266,15 +6296,31 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_height = height; intel_crtc_update_cursor(crtc, true); +} + +static int intel_crtc_cursor_set(struct drm_crtc *crtc, +struct drm_file *file, +uint32_t handle, +uint32_t width, uint32_t height) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int ret; + struct drm_i915_gem_object *obj, *old_obj; + uint32_t addr; + + ret = intel_crtc_cursor_prepare(crtc, file, handle, width, height, + &obj, &addr); + if (ret) + return ret; + + old_obj = intel_crtc->cursor_bo; + + intel_crtc_cursor_commit(crtc, handle, width, height, obj, addr)
[Intel-gfx] [PATCH 25/81] drm/i915: unstatic cursor functions for use with atomic modesetting
From: Ander Conselvan de Oliveira --- drivers/gpu/drm/i915/intel_display.c | 24 drivers/gpu/drm/i915/intel_drv.h | 13 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f25a07..2f72881 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6173,12 +6173,12 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, } } -static int intel_crtc_cursor_prepare(struct drm_crtc *crtc, -struct drm_file *file, -uint32_t handle, -uint32_t width, uint32_t height, -struct drm_i915_gem_object **obj_ret, -uint32_t *addr_ret) +int intel_crtc_cursor_prepare(struct drm_crtc *crtc, + struct drm_file *file, + uint32_t handle, + uint32_t width, uint32_t height, + struct drm_i915_gem_object **obj_ret, + uint32_t *addr_ret) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -6263,8 +6263,8 @@ fail: return ret; } -static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc, - struct drm_i915_gem_object *obj) +void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc, + struct drm_i915_gem_object *obj) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -6282,10 +6282,10 @@ static void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc, mutex_unlock(&dev->struct_mutex); } -static void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, -uint32_t width, uint32_t height, -struct drm_i915_gem_object *obj, -uint32_t addr) +void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, + uint32_t width, uint32_t height, + struct drm_i915_gem_object *obj, + uint32_t addr) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e77202c..785fa04 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -679,4 +679,17 @@ extern bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); +extern int intel_crtc_cursor_prepare(struct drm_crtc *crtc, +struct drm_file *file, +uint32_t handle, +uint32_t width, uint32_t height, +struct drm_i915_gem_object **obj_ret, +uint32_t *addr_ret); +extern void intel_crtc_cursor_bo_unref(struct drm_crtc *crtc, + struct drm_i915_gem_object *obj); +extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, +uint32_t width, uint32_t height, +struct drm_i915_gem_object *obj, +uint32_t addr); + #endif /* __INTEL_DRV_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 26/81] drm/i915: Unstatic intel_finish_fb()
From: Ville Syrjälä intel_finish_fb() will be used by the atomic modeset code, so make it non-static. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |2 +- drivers/gpu/drm/i915/intel_drv.h |1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2f72881..a184b70 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2182,7 +2182,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return dev_priv->display.update_plane(crtc, fb, x, y); } -static int +int intel_finish_fb(struct drm_framebuffer *old_fb) { struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 785fa04..59ca0c3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -590,6 +590,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj); +extern int intel_finish_fb(struct drm_framebuffer *old_fb); extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 22/81] drm/i915: Add intel_check_clock()
From: Ville Syrjälä intel_check_clock() can be used to check clock validity w/o modifying hardware state. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_drv.h |2 ++ drivers/gpu/drm/i915/intel_display.c | 34 ++ 2 files changed, 36 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ab0bd29..c41982e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1719,6 +1719,8 @@ extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_init_pch_refclk(struct drm_device *dev); +extern int intel_check_clock(struct drm_crtc *crtc, +const struct drm_display_mode *adjusted_mode); extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a2c664..dcd61fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5686,6 +5686,40 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, return ret; } +int intel_check_clock(struct drm_crtc *crtc, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock, reduced_clock; + bool has_reduced_clock = false; + bool ok; + + if (IS_HASWELL(dev)) { + if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) + return -EINVAL; + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, +&has_reduced_clock, +&reduced_clock); + } else + ok = true; + } else if (HAS_PCH_SPLIT(dev)) { + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, +&has_reduced_clock, &reduced_clock); + } else { + int num_connectors = 0; + bool is_dp = false; + int refclk; + + ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock, +&has_reduced_clock, &reduced_clock, +&refclk, &num_connectors, &is_dp); + } + + return ok ? 0 : -EINVAL; +} + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 29/81] drm/i915: Unstatic intel_crtc_update_sarea_pos()
From: Ville Syrjälä Make intel_crtc_update_sarea_pos() available to the atomic mode setting code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |2 +- drivers/gpu/drm/i915/intel_drv.h |1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9918dcb..f7190d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2209,7 +2209,7 @@ intel_finish_fb(struct drm_framebuffer *old_fb) return ret; } -static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y) +void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_master_private *master_priv; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c1fee22..a7d8df8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -694,5 +694,6 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, uint32_t addr); extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled); +extern void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y); #endif /* __INTEL_DRV_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 28/81] drm/i915: Unstatic intel_crtc_update_sarea()
From: Ville Syrjälä Make intel_crtc_update_sarea() available for the atomic mode setting code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |4 ++-- drivers/gpu/drm/i915/intel_drv.h |2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6522e1e..9918dcb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3652,8 +3652,8 @@ static void i9xx_crtc_off(struct drm_crtc *crtc) { } -static void intel_crtc_update_sarea(struct drm_crtc *crtc, - bool enabled) +void intel_crtc_update_sarea(struct drm_crtc *crtc, +bool enabled) { struct drm_device *dev = crtc->dev; struct drm_i915_master_private *master_priv; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 59ca0c3..c1fee22 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -693,4 +693,6 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, struct drm_i915_gem_object *obj, uint32_t addr); +extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled); + #endif /* __INTEL_DRV_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 30/81] drm/i915: Constify mode argument to intel_modeset_adjusted_mode()
From: Ville Syrjälä intel_modeset_adjusted_mode() doesn't modify the passed display mode. So pass it as const. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f7190d2..dac80c4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7401,7 +7401,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) static struct drm_display_mode * intel_modeset_adjusted_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 31/81] drm/i915: Unstatic intel_crtc_mode_fixup()
From: Ville Syrjälä Make intel_crtc_mode_fixup() available for the upcoming atomic modesetting code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |6 +++--- drivers/gpu/drm/i915/intel_drv.h |4 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dac80c4..2c2fcda 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3851,9 +3851,9 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) return encoder->get_hw_state(encoder, &pipe); } -static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool intel_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a7d8df8..ee6c85f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -696,4 +696,8 @@ extern void intel_crtc_cursor_commit(struct drm_crtc *crtc, uint32_t handle, extern void intel_crtc_update_sarea(struct drm_crtc *crtc, bool enabled); extern void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y); +extern bool intel_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + #endif /* __INTEL_DRV_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 32/81] drm/i915: Introduce intel_plane_regs
From: Ville Syrjälä intel_plane_regs can be used to shadow all the typical plane registers. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_drv.h | 14 ++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ee6c85f..b11510a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -194,6 +194,20 @@ struct intel_connector { struct edid *edid; }; +struct intel_plane_regs { + u32 cntr; + u32 linoff; + u32 stride; + u32 pos; + u32 size; + u32 keyval; + u32 keymsk; + u32 surf; + u32 keymaxval; + u32 tileoff; + u32 scale; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 27/81] drm/i915: Pull intel_pipe_set_base() out of the crtc_mode_set() functions
From: Ville Syrjälä intel_pipe_set_base() (un)pins the buffers, so it can't be called from the atomic modeset paths. Pull the intel_pipe_set_base() and watermark modifications out of i9xx_crtc_mode_set() and ironlake_crtc_mode_set() into intel_crtc_mode_set(), so that the former two can be used from the atomic modeset paths. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 35 - 1 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a184b70..6522e1e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4630,7 +4630,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, u32 dspcntr, pipeconf; bool ok, has_reduced_clock = false; bool is_dp = false; - int ret; ok = i9xx_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock, @@ -4738,11 +4737,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - ret = intel_pipe_set_base(crtc, x, y, fb); - - intel_update_watermarks(dev); - - return ret; + return 0; } static void ironlake_init_pch_refclk(struct drm_device *dev) @@ -5479,7 +5474,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool ok, has_reduced_clock = false; bool is_lvds = false, is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - int ret; bool dither, fdi_config_ok; for_each_encoder_on_crtc(dev, crtc, encoder) { @@ -5590,13 +5584,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); POSTING_READ(DSPCNTR(plane)); - ret = intel_pipe_set_base(crtc, x, y, fb); - - intel_update_watermarks(dev); - - intel_update_linetime_watermarks(dev, pipe, adjusted_mode); - - return fdi_config_ok ? ret : -EINVAL; + return fdi_config_ok ? 0 : -EINVAL; } static int haswell_crtc_mode_set(struct drm_crtc *crtc, @@ -5613,7 +5601,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int num_connectors = 0; bool is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - int ret; bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { @@ -5677,13 +5664,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); POSTING_READ(DSPCNTR(plane)); - ret = intel_pipe_set_base(crtc, x, y, fb); - - intel_update_watermarks(dev); - - intel_update_linetime_watermarks(dev, pipe, adjusted_mode); - - return ret; + return 0; } int intel_check_clock(struct drm_crtc *crtc, @@ -5738,6 +5719,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, x, y, fb); + + if (!ret) { + ret = intel_pipe_set_base(crtc, x, y, fb); + + intel_update_watermarks(dev); + + if (HAS_PCH_SPLIT(dev)) + intel_update_linetime_watermarks(dev, pipe, adjusted_mode); + } + drm_vblank_post_modeset(dev, pipe); if (ret != 0) -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 34/81] drm/i915: Split sprite update_plane() into calc+commit phases
From: Ville Syrjälä Separate the part that calculates the register values from the part that writes the registers. This will be useful in the atomic page flip code. Also move the watermark magic into a prepare function that can be performed outside the critical parts of the atomic page flip code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_drv.h|5 + drivers/gpu/drm/i915/intel_sprite.c | 416 ++- 2 files changed, 273 insertions(+), 148 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4798f54..05afdd1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -270,6 +270,11 @@ struct intel_plane { struct drm_intel_sprite_colorkey *key); void (*get_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); + void (*calc)(struct drm_plane *plane, struct drm_framebuffer *fb, +const struct intel_plane_coords *clip); + void (*prepare)(struct drm_plane *plane); + void (*commit)(struct drm_plane *plane); + struct intel_plane_regs regs; }; struct intel_watermark_params { diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index d64cefd..88644df 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -203,14 +203,13 @@ int intel_check_plane(const struct drm_plane *plane, } static void -ivb_update_plane(struct drm_plane *plane, -struct drm_framebuffer *fb, -const struct intel_plane_coords *coords) +ivb_calc_plane(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct intel_plane_coords *coords) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); - const struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; + const struct drm_i915_gem_object *obj; int crtc_x = coords->crtc_x; int crtc_y = coords->crtc_y; unsigned int crtc_w = coords->crtc_w; @@ -219,48 +218,56 @@ ivb_update_plane(struct drm_plane *plane, uint32_t y = coords->src_y; uint32_t src_w = coords->src_w; uint32_t src_h = coords->src_h; - int pipe = intel_plane->pipe; - u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + int pixel_size; + struct intel_plane_regs *regs = &intel_plane->regs; - sprctl = I915_READ(SPRCTL(pipe)); + if (!coords->visible) { + regs->cntr &= ~SPRITE_ENABLE; + /* Disable the scaler */ + regs->scale = 0; + return; + } + + obj = to_intel_framebuffer(fb)->obj; + pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); /* Mask out pixel format bits in case we change it */ - sprctl &= ~SPRITE_PIXFORMAT_MASK; - sprctl &= ~SPRITE_RGB_ORDER_RGBX; - sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; - sprctl &= ~SPRITE_TILED; + regs->cntr &= ~(SPRITE_PIXFORMAT_MASK | + SPRITE_RGB_ORDER_RGBX | + SPRITE_YUV_BYTE_ORDER_MASK | + SPRITE_TILED | + SPRITE_ENABLE); switch (fb->pixel_format) { case DRM_FORMAT_XBGR: - sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; + regs->cntr |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; break; case DRM_FORMAT_XRGB: - sprctl |= SPRITE_FORMAT_RGBX888; + regs->cntr |= SPRITE_FORMAT_RGBX888; break; case DRM_FORMAT_YUYV: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; break; case DRM_FORMAT_YVYU: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; break; case DRM_FORMAT_UYVY: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; break; case DRM_FORMAT_VYUY: - sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; + regs->cntr |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; break; default: BUG(); } if (obj->tiling_mode != I915_TILING_NONE) - sprctl |= SPRITE_TILED; + regs->cntr |= SPRITE_TILED; /* must disable */ - sprctl |= SPRITE_TRICKLE_FEED_DISABLE; - sprctl |= SPR
[Intel-gfx] [PATCH 36/81] drm/i915: Add support for atomic modesetting completion events
From: Ville Syrjälä Send completion events when the atomic modesetting operations has finished succesfully. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 195 ++- 1 files changed, 192 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4899f8c..3adb140 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -53,6 +53,7 @@ struct intel_plane_state { bool dirty; bool pinned; bool changed; + struct drm_pending_atomic_event *event; struct { struct drm_crtc *crtc; @@ -74,6 +75,7 @@ struct intel_crtc_state { unsigned long connectors_bitmask; unsigned long encoders_bitmask; bool changed; + struct drm_pending_atomic_event *event; struct { bool enabled; @@ -922,6 +924,111 @@ int intel_commit_plane_nopin(struct drm_plane *plane, struct drm_framebuffer *fb, const struct intel_plane_coords *coords); +static struct drm_pending_atomic_event *alloc_event(struct drm_device *dev, + struct drm_file *file_priv, + uint64_t user_data) +{ + struct drm_pending_atomic_event *e; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + if (file_priv->event_space < sizeof e->event) { + spin_unlock_irqrestore(&dev->event_lock, flags); + return ERR_PTR(-ENOSPC); + } + + file_priv->event_space -= sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (!e) { + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return ERR_PTR(-ENOMEM); + } + + e->event.base.type = DRM_EVENT_ATOMIC_COMPLETE; + e->event.base.length = sizeof e->event; + e->event.user_data = user_data; + e->base.event = &e->event.base; + e->base.file_priv = file_priv; + e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; + + return e; +} + +static void free_event(struct drm_pending_atomic_event *e) +{ + e->base.file_priv->event_space += sizeof e->event; + kfree(e); +} + +static void queue_event(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_pending_atomic_event *e) +{ + struct timeval tvbl; + + if (crtc) { + int pipe = to_intel_crtc(crtc)->pipe; + + /* FIXME this is wrong for flips that are completed not at vblank */ + e->event.sequence = drm_vblank_count_and_time(dev, pipe, &tvbl); + e->event.tv_sec = tvbl.tv_sec; + e->event.tv_usec = tvbl.tv_usec; + } else { + e->event.sequence = 0; + e->event.tv_sec = 0; + e->event.tv_usec = 0; + } + + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); +} + +static void queue_remaining_events(struct drm_device *dev, struct intel_atomic_state *s) +{ + int i; + + for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct intel_crtc_state *st = &s->crtc[i]; + + if (st->event) { + if (st->old.fb) + st->event->event.old_fb_id = st->old.fb->base.id; + + spin_lock_irq(&dev->event_lock); + queue_event(dev, st->crtc, st->event); + spin_unlock_irq(&dev->event_lock); + + st->event = NULL; + } + } + + for (i = 0; i < dev->mode_config.num_plane; i++) { + struct intel_plane_state *st = &s->plane[i]; + struct drm_crtc *crtc; + + if (!st->event) + continue; + + crtc = st->plane->crtc; + if (!crtc) + crtc = st->old.crtc; + + if (st->old.fb) + st->event->event.old_fb_id = st->old.fb->base.id; + + spin_lock_irq(&dev->event_lock); + queue_event(dev, crtc, st->event); + spin_unlock_irq(&dev->event_lock); + + st->event = NULL; + } +} + static void swap_old_new(struct drm_device *dev, struct intel_atomic_state *s) { @@ -1426,6 +1533,73 @@ static void update_crtc(struct drm_device *dev, } } +static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s) +{ + int i; + + for (i = 0; i < dev->mode_config.num_crtc; i++) { +
[Intel-gfx] [PATCH 37/81] drm/i915: Add atomic page flip support
From: Ville Syrjälä Add support for the DRM_MODE_ATOMIC_NONBLOCK flag. The drm_flip helper provides the necessary logic to track the progress of the flips. drm_flip is driven by a few extra calls from the interrupt handling and crtc_disable code paths. Since the hardware doesn't provide inter-plane synchronization, some extra software magic is required to avoid flips for multiple planes ending up on the wrong sides of the vblank leading edge. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_dma.c |3 + drivers/gpu/drm/i915/i915_drv.h |4 + drivers/gpu/drm/i915/i915_irq.c | 16 +- drivers/gpu/drm/i915/intel_atomic.c | 622 +- drivers/gpu/drm/i915/intel_display.c |2 + drivers/gpu/drm/i915/intel_drv.h |7 + 6 files changed, 637 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 392c9a1..8501bf3 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1764,6 +1764,8 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file) idr_init(&file_priv->context_idr); + INIT_LIST_HEAD(&file_priv->pending_flips); + return 0; } @@ -1804,6 +1806,7 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { i915_gem_context_close(dev, file_priv); i915_gem_release(dev, file_priv); + intel_atomic_free_events(dev, file_priv); } void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 66b3b64..0bafe7f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -957,6 +958,8 @@ typedef struct drm_i915_private { /* Old dri1 support infrastructure, beware the dragons ya fools entering * here! */ struct i915_dri1_state dri1; + + struct drm_flip_driver flip_driver; } drm_i915_private_t; /* Iterate over initialised rings */ @@ -1179,6 +1182,7 @@ struct drm_i915_file_private { struct list_head request_list; } mm; struct idr context_idr; + struct list_head pending_flips; }; #define INTEL_INFO(dev)(((struct drm_i915_private *) (dev)->dev_private)->info) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d02e022..430f201 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -581,8 +581,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); for_each_pipe(pipe) { - if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) { drm_handle_vblank(dev, pipe); + intel_atomic_handle_vblank(dev, pipe); + } if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { intel_prepare_page_flip(dev, pipe); @@ -727,8 +729,10 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) intel_opregion_gse_intr(dev); for (i = 0; i < 3; i++) { - if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) + if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) { drm_handle_vblank(dev, i); + intel_atomic_handle_vblank(dev, i); + } if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) { intel_prepare_page_flip(dev, i); intel_finish_page_flip_plane(dev, i); @@ -807,11 +811,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); - if (de_iir & DE_PIPEA_VBLANK) + if (de_iir & DE_PIPEA_VBLANK) { drm_handle_vblank(dev, 0); + intel_atomic_handle_vblank(dev, 0); + } - if (de_iir & DE_PIPEB_VBLANK) + if (de_iir & DE_PIPEB_VBLANK) { drm_handle_vblank(dev, 1); + intel_atomic_handle_vblank(dev, 1); + } if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 3adb140..238a843 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -26,6 +26,7 @@ #include #include +#include #include "intel_drv.h" @@ -47,6 +48,20 @@ static struct drm_property *prop_cursor_y; static struct drm_property *prop_cursor_w; static s
[Intel-gfx] [PATCH 38/81] drm/i915: Unstatic intel_enable_primary() and intel_disable_primary()
From: Ville Syrjälä intel_enable_primary() and intel_disable_primary() are needed in the atomic mode setting code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_drv.h|3 +++ drivers/gpu/drm/i915/intel_sprite.c |4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cd37428..92a9518 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -730,4 +730,7 @@ extern void intel_atomic_fini(struct drm_device *dev); extern void intel_atomic_free_events(struct drm_device *dev, struct drm_file *file); extern void intel_atomic_handle_vblank(struct drm_device *dev, int pipe); +extern void intel_enable_primary(struct drm_crtc *crtc); +extern void intel_disable_primary(struct drm_crtc *crtc); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 88644df..693b265 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -610,7 +610,7 @@ void intel_calc_sprite(struct drm_plane *plane, ilk_calc_plane(plane, fb, coords); } -static void +void intel_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -629,7 +629,7 @@ intel_enable_primary(struct drm_crtc *crtc) dev_priv->display.commit_plane(crtc); } -static void +void intel_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 33/81] drm/i915: Split primary plane update_plane() into calc+commit phases
From: Ville Syrjälä Separate the part that calculates the register values from the part that writes the registers. This will be useful in the atomic page flip code. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_drv.h |3 + drivers/gpu/drm/i915/intel_display.c | 154 ++ drivers/gpu/drm/i915/intel_drv.h |1 + 3 files changed, 105 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c41982e..66b3b64 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -297,6 +297,9 @@ struct drm_i915_display_funcs { struct drm_i915_gem_object *obj); int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); + int (*calc_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y); + void (*commit_plane)(struct drm_crtc *crtc); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2c2fcda..c0db749 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1979,8 +1979,30 @@ unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y, return tile_rows * pitch * 8 + tiles * 4096; } -static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, -int x, int y) +static void intel_commit_plane(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane; + const struct intel_plane_regs *regs = &intel_crtc->primary_regs; + + I915_WRITE(DSPCNTR(plane), regs->cntr); + I915_WRITE(DSPSTRIDE(plane), regs->stride); + + if (IS_HASWELL(dev)) { + I915_WRITE(DSPOFFSET(plane), regs->tileoff); + I915_WRITE(DSPSURF(plane), regs->surf); + } else if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(DSPTILEOFF(plane), regs->tileoff); + I915_WRITE(DSPLINOFF(plane), regs->linoff); + I915_WRITE(DSPSURF(plane), regs->surf); + } else + I915_WRITE(DSPADDR(plane), regs->linoff); +} + +static int i9xx_calc_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1989,9 +2011,8 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long linear_offset; - u32 dspcntr; - u32 reg; unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0); + struct intel_plane_regs *regs = &intel_crtc->primary_regs; switch (plane) { case 0: @@ -2005,36 +2026,35 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); + regs->cntr = I915_READ(DSPCNTR(plane)); /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + regs->cntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->pixel_format) { case DRM_FORMAT_C8: - dspcntr |= DISPPLANE_8BPP; + regs->cntr |= DISPPLANE_8BPP; break; case DRM_FORMAT_XRGB1555: case DRM_FORMAT_ARGB1555: - dspcntr |= DISPPLANE_BGRX555; + regs->cntr |= DISPPLANE_BGRX555; break; case DRM_FORMAT_RGB565: - dspcntr |= DISPPLANE_BGRX565; + regs->cntr |= DISPPLANE_BGRX565; break; case DRM_FORMAT_XRGB: case DRM_FORMAT_ARGB: - dspcntr |= DISPPLANE_BGRX888; + regs->cntr |= DISPPLANE_BGRX888; break; case DRM_FORMAT_XBGR: case DRM_FORMAT_ABGR: - dspcntr |= DISPPLANE_RGBX888; + regs->cntr |= DISPPLANE_RGBX888; break; case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: - dspcntr |= DISPPLANE_BGRX101010; + regs->cntr |= DISPPLANE_BGRX101010; break; case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: - dspcntr |= DISPPLANE_RGBX101010; + regs->cntr |= DISPPLANE_RGBX101010; break; default: DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); @@ -
[Intel-gfx] [PATCH 39/81] drm/i915: Respect primary_disabled in crtc_enable()
From: Ville Syrjälä Check primary_disabled state before enabling the primary plane in crtc_enable() hooks. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |9 ++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7394aca..957907c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3349,7 +3349,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); intel_enable_pipe(dev_priv, pipe, is_pch_port); - intel_enable_plane(dev_priv, plane, pipe); + if (!intel_crtc->primary_disabled) + intel_enable_plane(dev_priv, plane, pipe); if (is_pch_port) ironlake_pch_enable(crtc); @@ -3429,7 +3430,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_func(crtc); intel_enable_pipe(dev_priv, pipe, is_pch_port); - intel_enable_plane(dev_priv, plane, pipe); + if (!intel_crtc->primary_disabled) + intel_enable_plane(dev_priv, plane, pipe); if (is_pch_port) lpt_pch_enable(crtc); @@ -3644,7 +3646,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_enable_pll(dev_priv, pipe); intel_enable_pipe(dev_priv, pipe, false); - intel_enable_plane(dev_priv, plane, pipe); + if (!intel_crtc->primary_disabled) + intel_enable_plane(dev_priv, plane, pipe); intel_crtc_load_lut(crtc); intel_update_fbc(dev); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 40/81] drm/i915: Enable/disable primary plane in calc_plane()
From: Ville Syrjälä Check the active and primary_disabled flags and set the DISPLAY_PLANE_ENABLE bit accordingly in calc_plane() hook for the primary plane. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 957907c..9903456 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2068,6 +2068,11 @@ static int i9xx_calc_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, regs->cntr &= ~DISPPLANE_TILED; } + if (intel_crtc->active && !intel_crtc->primary_disabled) + regs->cntr |= DISPLAY_PLANE_ENABLE; + else + regs->cntr &= ~DISPLAY_PLANE_ENABLE; + linear_offset = y * fb->pitches[0] + x * cpp; if (INTEL_INFO(dev)->gen >= 4) { @@ -2175,6 +2180,11 @@ static int ironlake_calc_plane(struct drm_crtc *crtc, /* must disable */ regs->cntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + if (intel_crtc->active && !intel_crtc->primary_disabled) + regs->cntr |= DISPLAY_PLANE_ENABLE; + else + regs->cntr &= ~DISPLAY_PLANE_ENABLE; + linear_offset = y * fb->pitches[0] + x * cpp; intel_crtc->dspaddr_offset = intel_gen4_compute_offset_xtiled(&x, &y, -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 41/81] drm/i915: Add primary plane disable logic to atomic mode setting code
From: Ville Syrjälä Enable/disable the primary plane accordingly when the sprite plane coverage changes. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 41 +++ 1 files changed, 41 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 238a843..41885fa 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -93,6 +93,7 @@ struct intel_crtc_state { bool changed; struct drm_pending_atomic_event *event; struct intel_flip *flip; + bool primary_disabled; struct { bool enabled; @@ -318,6 +319,8 @@ static void *intel_atomic_begin(struct drm_device *dev, struct drm_file *file, s->old.connectors_bitmask = s->connectors_bitmask; s->old.encoders_bitmask = s->encoders_bitmask; + + s->primary_disabled = intel_crtc->primary_disabled; } i = 0; @@ -1157,6 +1160,9 @@ static int apply_config(struct drm_device *dev, intel_crtc->cursor_addr); } + if (!st->primary_disabled) + intel_enable_primary(crtc); + for (j = 0; j < dev->mode_config.num_plane; j++) { struct intel_plane_state *pst = &s->plane[j]; struct drm_plane *plane = pst->plane; @@ -1170,6 +1176,9 @@ static int apply_config(struct drm_device *dev, else if (!pst->coords.visible && pst->old.crtc == crtc) intel_plane->disable_plane(plane); } + + if (st->primary_disabled) + intel_disable_primary(crtc); } /* don't restore the old state in end() */ @@ -1207,6 +1216,7 @@ static void restore_state(struct drm_device *dev, intel_crtc->cursor_width = s->saved_crtcs[i].cursor_width; intel_crtc->cursor_height = s->saved_crtcs[i].cursor_height; intel_crtc->cursor_visible = s->saved_crtcs[i].cursor_visible; + intel_crtc->primary_disabled = s->saved_crtcs[i].primary_disabled; i++; } @@ -1346,6 +1356,28 @@ static int check_crtc(struct intel_crtc_state *s) return 0; } +static void update_primary_visibility(struct drm_device *dev, + struct intel_atomic_state *s, + const struct drm_crtc *crtc, + const struct drm_plane *plane, + const struct intel_plane_coords *coords) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool primary_disabled = + coords->visible && + coords->crtc_x == 0 && + coords->crtc_y == 0 && + coords->crtc_w == crtc->mode.hdisplay && + coords->crtc_h == crtc->mode.vdisplay; + + if (primary_disabled != intel_crtc->primary_disabled) { + struct intel_crtc_state *st = get_crtc_state(dev, s, crtc); + st->fb_dirty = true; + st->primary_disabled = primary_disabled; + s->dirty = true; + } +} + static int intel_atomic_check(struct drm_device *dev, void *state) { struct intel_atomic_state *s = state; @@ -1430,6 +1462,12 @@ static int intel_atomic_check(struct drm_device *dev, void *state) ret = intel_check_plane(plane, plane->crtc, plane->fb, &st->coords); if (ret) return ret; + + /* FIXME doesn't correctly handle cases where plane moves between crtcs */ + if (plane->crtc) + update_primary_visibility(dev, s, plane->crtc, plane, &st->coords); + else if (st->old.crtc) + update_primary_visibility(dev, s, st->old.crtc, plane, &st->coords); } return 0; @@ -2295,6 +2333,9 @@ static void atomic_pipe_commit(struct drm_device *dev, intel_flip->crtc = crtc; + /* update primary_disabled befoer calc_plane() */ + intel_crtc->primary_disabled = st->primary_disabled; + /* should already be checked so can't fail */ /* FIXME refactor the failing parts? */ dev_priv->display.calc_plane(crtc, crtc->fb, crtc->x, crtc->y); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 42/81] drm: Add missing EXPORT_SYMBOL()s for drm_flip
From: Ander Conselvan de Oliveira --- drivers/gpu/drm/drm_flip.c | 11 +++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_flip.c b/drivers/gpu/drm/drm_flip.c index 6ccc3f8..a20e6a4 100644 --- a/drivers/gpu/drm/drm_flip.c +++ b/drivers/gpu/drm/drm_flip.c @@ -24,6 +24,7 @@ * Ville Syrjälä */ +#include #include static void drm_flip_driver_cleanup(struct work_struct *work) @@ -141,6 +142,7 @@ void drm_flip_helper_init(struct drm_flip_helper *helper, helper->driver = driver; helper->funcs = funcs; } +EXPORT_SYMBOL(drm_flip_helper_init); void drm_flip_helper_clear(struct drm_flip_helper *helper) { @@ -176,6 +178,7 @@ void drm_flip_helper_clear(struct drm_flip_helper *helper) if (need_cleanup) queue_work(driver->wq, &driver->cleanup_work); } +EXPORT_SYMBOL(drm_flip_helper_clear); void drm_flip_helper_fini(struct drm_flip_helper *helper) { @@ -186,6 +189,7 @@ void drm_flip_helper_fini(struct drm_flip_helper *helper) flush_work_sync(&driver->finish_work); flush_work_sync(&driver->cleanup_work); } +EXPORT_SYMBOL(drm_flip_helper_fini); void drm_flip_helper_vblank(struct drm_flip_helper *helper) { @@ -223,6 +227,7 @@ void drm_flip_helper_vblank(struct drm_flip_helper *helper) if (need_cleanup) queue_work(driver->wq, &driver->cleanup_work); } +EXPORT_SYMBOL(drm_flip_helper_vblank); void drm_flip_driver_init(struct drm_flip_driver *driver, const struct drm_flip_driver_funcs *funcs) @@ -239,6 +244,7 @@ void drm_flip_driver_init(struct drm_flip_driver *driver, driver->wq = create_singlethread_workqueue("drm_flip"); } +EXPORT_SYMBOL(drm_flip_driver_init); void drm_flip_driver_fini(struct drm_flip_driver *driver) { @@ -248,6 +254,7 @@ void drm_flip_driver_fini(struct drm_flip_driver *driver) WARN_ON(!list_empty(&driver->finish_list)); WARN_ON(!list_empty(&driver->cleanup_list)); } +EXPORT_SYMBOL(drm_flip_driver_fini); void drm_flip_driver_schedule_flips(struct drm_flip_driver *driver, struct list_head *flips) @@ -298,6 +305,7 @@ void drm_flip_driver_schedule_flips(struct drm_flip_driver *driver, if (need_cleanup) queue_work(driver->wq, &driver->cleanup_work); } +EXPORT_SYMBOL(drm_flip_driver_schedule_flips); void drm_flip_driver_prepare_flips(struct drm_flip_driver *driver, struct list_head *flips) @@ -311,6 +319,7 @@ void drm_flip_driver_prepare_flips(struct drm_flip_driver *driver, helper->funcs->prepare(flip); } } +EXPORT_SYMBOL(drm_flip_driver_prepare_flips); void drm_flip_driver_complete_flips(struct drm_flip_driver *driver, struct list_head *flips) @@ -365,6 +374,7 @@ void drm_flip_driver_complete_flips(struct drm_flip_driver *driver, if (need_cleanup) queue_work(driver->wq, &driver->cleanup_work); } +EXPORT_SYMBOL(drm_flip_driver_complete_flips); void drm_flip_init(struct drm_flip *flip, struct drm_flip_helper *helper) @@ -374,3 +384,4 @@ void drm_flip_init(struct drm_flip *flip, flip->finished = false; INIT_LIST_HEAD(&flip->list); } +EXPORT_SYMBOL(drm_flip_init); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 45/81] drm/i915: Move standard properties under mode_config
From: Ville Syrjälä Standard connector properties are kept in the mode_config structure. Move the CRTC and plane properties there as well. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 293 +++ include/drm/drm_crtc.h | 19 +++ 2 files changed, 175 insertions(+), 137 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 0e37cf5..0def947 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -30,24 +30,6 @@ #include "intel_drv.h" -static struct drm_property *prop_src_x; -static struct drm_property *prop_src_y; -static struct drm_property *prop_src_w; -static struct drm_property *prop_src_h; -static struct drm_property *prop_crtc_x; -static struct drm_property *prop_crtc_y; -static struct drm_property *prop_crtc_w; -static struct drm_property *prop_crtc_h; -static struct drm_property *prop_fb_id; -static struct drm_property *prop_crtc_id; -static struct drm_property *prop_mode; -static struct drm_property *prop_connector_ids; -static struct drm_property *prop_cursor_id; -static struct drm_property *prop_cursor_x; -static struct drm_property *prop_cursor_y; -static struct drm_property *prop_cursor_w; -static struct drm_property *prop_cursor_h; - struct intel_flip { struct drm_flip base; u32 vbl_count; @@ -368,27 +350,28 @@ static int plane_set(struct intel_atomic_state *s, uint64_t value) { struct drm_plane *plane = state->plane; + struct drm_mode_config *config = &plane->dev->mode_config; struct drm_mode_object *obj; state->changed = true; - if (prop == prop_src_x) { + if (prop == config->src_x_prop) { plane->src_x = value; - } else if (prop == prop_src_y) { + } else if (prop == config->src_y_prop) { plane->src_y = value; - } else if (prop == prop_src_w) { + } else if (prop == config->src_w_prop) { plane->src_w = value; - } else if (prop == prop_src_h) { + } else if (prop == config->src_h_prop) { plane->src_h = value; - } else if (prop == prop_crtc_x) { + } else if (prop == config->crtc_x_prop) { plane->crtc_x = value; - } else if (prop == prop_crtc_y) { + } else if (prop == config->crtc_y_prop) { plane->crtc_y = value; - } else if (prop == prop_crtc_w) { + } else if (prop == config->crtc_w_prop) { plane->crtc_w = value; - } else if (prop == prop_crtc_h) { + } else if (prop == config->crtc_h_prop) { plane->crtc_h = value; - } else if (prop == prop_crtc_id) { + } else if (prop == config->crtc_id_prop) { if (value) { obj = drm_mode_object_find(plane->dev, value, DRM_MODE_OBJECT_CRTC); if (!obj) { @@ -398,7 +381,7 @@ static int plane_set(struct intel_atomic_state *s, plane->crtc = obj_to_crtc(obj); } else plane->crtc = NULL; - } else if (prop == prop_fb_id) { + } else if (prop == config->fb_id_prop) { if (value) { obj = drm_mode_object_find(plane->dev, value, DRM_MODE_OBJECT_FB); if (!obj) { @@ -422,16 +405,17 @@ static int crtc_set(struct intel_atomic_state *s, uint64_t value, const void *blob_data) { struct drm_crtc *crtc = state->crtc; + struct drm_mode_config *config = &crtc->dev->mode_config; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_mode_object *obj; state->changed = true; - if (prop == prop_src_x) { + if (prop == config->src_x_prop) { crtc->x = value; - } else if (prop == prop_src_y) { + } else if (prop == config->src_y_prop) { crtc->y = value; - } else if (prop == prop_mode) { + } else if (prop == config->mode_prop) { const struct drm_mode_modeinfo *umode = blob_data; if (value != 0 && value != sizeof *umode) { @@ -462,7 +446,7 @@ static int crtc_set(struct intel_atomic_state *s, drm_mode_destroy(crtc->dev, mode); } else crtc->enabled = false; - } else if (prop == prop_fb_id) { + } else if (prop == config->fb_id_prop) { if (value) { obj = drm_mode_object_find(crtc->dev, value, DRM_MODE_OBJECT_FB); if (!obj) { @@ -472,7 +456,7 @@ static int crtc_set(struct intel_atomic_state *s, crtc->fb = obj_to_fb(obj); } else crtc->fb = NULL; - } else if (prop == prop_connector_ids) { + } else if (prop == config->connector_ids_prop) {
[Intel-gfx] [PATCH 48/81] drm/i915: Update CRTC properties after modeset
From: Ville Syrjälä Update cursor related CRTC properties after a modeset. The cursor properties aren't handled by the drm core since not all CRTCs have cursors. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 15 +++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 566bf29..321c840 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6368,6 +6368,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, if (old_obj) intel_crtc_cursor_bo_unref(crtc, old_obj); + intel_crtc_update_properties(crtc); + return 0; } @@ -6380,6 +6382,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) intel_crtc_update_cursor(crtc, true); + intel_crtc_update_properties(crtc); + return 0; } @@ -7341,6 +7345,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, trace_i915_flip_request(intel_crtc->plane, obj); + intel_crtc_update_properties(crtc); + return 0; cleanup_pending: @@ -8067,6 +8073,7 @@ next_encoder: static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; + struct drm_crtc *crtc; struct drm_mode_set save_set; struct intel_set_config *config; int ret; @@ -8140,6 +8147,10 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_set_config_free(config); + /* changes in one CRTC can affect the others */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + intel_crtc_update_properties(crtc); + return 0; fail: @@ -8151,6 +8162,10 @@ fail: save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); + /* changes in one CRTC can affect the others */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + intel_crtc_update_properties(crtc); + out_config: intel_set_config_free(config); return ret; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 43/81] drm/i915: Clear flip helpers for sprites too
From: Ville Syrjälä Don't leave stale flips hanging around the sprites' flip helpers when the crtc is being disabled. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 15 +++ drivers/gpu/drm/i915/intel_display.c |4 ++-- drivers/gpu/drm/i915/intel_drv.h |1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 41885fa..41fd0d5 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -2449,3 +2449,18 @@ void intel_atomic_handle_vblank(struct drm_device *dev, int pipe) drm_flip_helper_vblank(&intel_plane->flip_helper); } } + +void intel_atomic_clear_flips(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; + int pipe = intel_crtc->pipe; + + drm_flip_helper_clear(&intel_crtc->flip_helper); + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) { + if (intel_plane->pipe == pipe) + drm_flip_helper_clear(&intel_plane->flip_helper); + } +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9903456..566bf29 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3566,7 +3566,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) encoder->disable(encoder); intel_crtc_wait_for_pending_flips(crtc); - drm_flip_helper_clear(&intel_crtc->flip_helper); + intel_atomic_clear_flips(crtc); drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); @@ -3688,7 +3688,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_wait_for_pending_flips(crtc); - drm_flip_helper_clear(&intel_crtc->flip_helper); + intel_atomic_clear_flips(crtc); drm_vblank_off(dev, pipe); intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 92a9518..5b0789f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -729,6 +729,7 @@ extern int intel_atomic_init(struct drm_device *dev); extern void intel_atomic_fini(struct drm_device *dev); extern void intel_atomic_free_events(struct drm_device *dev, struct drm_file *file); extern void intel_atomic_handle_vblank(struct drm_device *dev, int pipe); +extern void intel_atomic_clear_flips(struct drm_crtc *crtc); extern void intel_enable_primary(struct drm_crtc *crtc); extern void intel_disable_primary(struct drm_crtc *crtc); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 51/81] drm/i915: Unstatic intel_modeset_update_staged_output_state()
From: Ville Syrjälä The atomic code needs intel_modeset_update_staged_output_state(). Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c |2 +- drivers/gpu/drm/i915/intel_drv.h |2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 451cc3d..c84a839 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7423,7 +7423,7 @@ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, * Updates the staged output configuration state, e.g. after we've read out the * current hw state. */ -static void intel_modeset_update_staged_output_state(struct drm_device *dev) +void intel_modeset_update_staged_output_state(struct drm_device *dev) { struct intel_encoder *encoder; struct intel_connector *connector; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1230c1b..24dc192 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -737,4 +737,6 @@ extern void intel_disable_primary(struct drm_crtc *crtc); extern void intel_crtc_attach_properties(struct drm_crtc *crtc); extern void intel_crtc_update_properties(struct drm_crtc *crtc); +extern void intel_modeset_update_staged_output_state(struct drm_device *dev); + #endif /* __INTEL_DRV_H__ */ -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 52/81] drm/i915: Update new_crtc and new_encoder fields after atomic modeset
From: Ville Syrjälä The i915 modeset logic requires that these be kept in sync with the other crtc and encoder pointers. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e58ec3f..c5558cc 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -1701,6 +1701,8 @@ static int intel_atomic_commit(struct drm_device *dev, void *state) update_props(dev, s); + intel_modeset_update_staged_output_state(dev); + return 0; } -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 47/81] drm: Update standard plane properties after update_plane/disable_plane
From: Ville Syrjälä Keep the new plane properties when doing operations through the legacy code paths. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c |6 ++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 897ff46..9d8738f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -407,6 +407,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) /* disconnect the plane from the fb and crtc: */ plane->fb = NULL; plane->crtc = NULL; + + drm_plane_update_properties(plane); } } @@ -1780,6 +1782,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, plane->funcs->disable_plane(plane); plane->crtc = NULL; plane->fb = NULL; + + drm_plane_update_properties(plane); goto out; } @@ -1863,6 +1867,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, plane->src_y = plane_req->src_y; plane->src_w = plane_req->src_w; plane->src_h = plane_req->src_h; + + drm_plane_update_properties(plane); } out: -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 44/81] drm/i915: Refactor property handling in atomic code
From: Ville Syrjälä Move the property code around a bit to make it easier to move it out to the drm core later. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 423 --- drivers/gpu/drm/i915/intel_drv.h|3 + include/drm/drm_crtc.h | 12 + 3 files changed, 252 insertions(+), 186 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 41fd0d5..0e37cf5 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -1473,87 +1473,6 @@ static int intel_atomic_check(struct drm_device *dev, void *state) return 0; } -static void update_plane_props(struct drm_plane *plane) -{ - struct drm_mode_object *obj = &plane->base; - - drm_object_property_set_value(obj, prop_src_x, plane->src_x); - drm_object_property_set_value(obj, prop_src_y, plane->src_y); - drm_object_property_set_value(obj, prop_src_w, plane->src_w); - drm_object_property_set_value(obj, prop_src_h, plane->src_h); - - drm_object_property_set_value(obj, prop_crtc_x, plane->crtc_x); - drm_object_property_set_value(obj, prop_crtc_y, plane->crtc_y); - drm_object_property_set_value(obj, prop_crtc_w, plane->crtc_w); - drm_object_property_set_value(obj, prop_crtc_h, plane->crtc_h); - - drm_object_property_set_value(obj, prop_fb_id, plane->fb ? plane->fb->base.id : 0); - drm_object_property_set_value(obj, prop_crtc_id, plane->crtc ? plane->crtc->base.id : 0); -} - -static int update_prop_connector_ids(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_connector *connector; - uint64_t value = 0; - int i = 0; - uint32_t connector_ids[dev->mode_config.num_connector]; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && connector->encoder->crtc == crtc) - connector_ids[i++] = connector->base.id; - } - - if (i) { - drm_property_blob_replace_data(crtc->connector_ids_blob, - i * sizeof connector_ids[0], connector_ids); - value = crtc->connector_ids_blob->base.id; - } else - drm_property_blob_replace_data(crtc->connector_ids_blob, 0, NULL); - - drm_object_property_set_value(&crtc->base, prop_connector_ids, value); - - return 0; -} - -static int update_prop_mode(struct drm_crtc *crtc) -{ - uint64_t value = 0; - - if (crtc->enabled) { - struct drm_mode_modeinfo umode; - - drm_crtc_convert_to_umode(&umode, &crtc->mode); - drm_property_blob_replace_data(crtc->mode_blob, sizeof umode, &umode); - value = crtc->mode_blob->base.id; - } else - drm_property_blob_replace_data(crtc->mode_blob, 0, NULL); - - drm_object_property_set_value(&crtc->base, prop_mode, value); - - return 0; -} - -static void update_crtc_props(struct drm_crtc *crtc) -{ - struct drm_mode_object *obj = &crtc->base; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - drm_object_property_set_value(obj, prop_src_x, crtc->x); - drm_object_property_set_value(obj, prop_src_y, crtc->y); - - drm_object_property_set_value(obj, prop_fb_id, crtc->fb ? crtc->fb->base.id : 0); - - drm_object_property_set_value(obj, prop_cursor_id, intel_crtc->cursor_handle); - drm_object_property_set_value(obj, prop_cursor_x, intel_crtc->cursor_x); - drm_object_property_set_value(obj, prop_cursor_y, intel_crtc->cursor_y); - drm_object_property_set_value(obj, prop_cursor_w, intel_crtc->cursor_width); - drm_object_property_set_value(obj, prop_cursor_h, intel_crtc->cursor_height); - - update_prop_mode(crtc); - update_prop_connector_ids(crtc); -} - static void update_props(struct drm_device *dev, struct intel_atomic_state *s) { @@ -1565,7 +1484,7 @@ static void update_props(struct drm_device *dev, if (!st->fb_dirty && !st->mode_dirty) continue; - update_crtc_props(st->crtc); + intel_crtc_update_properties(st->crtc); } for (i = 0; i < dev->mode_config.num_plane; i++) { @@ -1574,7 +1493,7 @@ static void update_props(struct drm_device *dev, if (!st->dirty) continue; - update_plane_props(st->plane); + drm_plane_update_properties(st->plane); } } @@ -1829,32 +1748,6 @@ static const struct drm_atomic_funcs intel_atomic_funcs = { .end = intel_atomic_end, }; -static struct { - struct drm_property **prop; - const char *name; - uint64_t min; - uint64_t max; -} props[] = { - { &prop_src_x, "SRC_X", 0, UINT_MAX }, - { &prop_src_y, "
[Intel-gfx] [PATCH 54/81] drm/i915: Kill the pending_flip counter manipulations
From: Ville Syrjälä The pending_flip counter is probably going to be remove entirely, along with i915_gem_execbuffer_wait_for_flips() so don't even try to use it. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 74 +-- 1 files changed, 2 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 1fce359..ac7fe88 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -1536,45 +1536,9 @@ static void atomic_pipe_commit(struct drm_device *dev, struct intel_atomic_state *state, int pipe); -static int apply_nonblocking(struct drm_device *dev, struct intel_atomic_state *s) +static void apply_nonblocking(struct drm_device *dev, struct intel_atomic_state *s) { struct intel_crtc *intel_crtc; - int i; - - for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct intel_crtc_state *st = &s->crtc[i]; - struct intel_crtc *intel_crtc = to_intel_crtc(st->crtc); - struct drm_i915_gem_object *obj; - - if (!st->old.fb) - continue; - - obj = to_intel_framebuffer(st->old.fb)->obj; - - /* Only one bit per plane in pending_flips */ - if (atomic_read(&obj->pending_flip) & (1 << intel_crtc->plane)) - return -EBUSY; - } - - for (i = 0; i < dev->mode_config.num_plane; i++) { - struct intel_plane_state *st = &s->plane[i]; - struct intel_plane *intel_plane = to_intel_plane(st->plane); - struct drm_i915_gem_object *obj; - - if (!st->old.fb) - continue; - - obj = to_intel_framebuffer(st->old.fb)->obj; - - if (!st->old.fb) - continue; - - obj = to_intel_framebuffer(st->old.fb)->obj; - - /* Only one bit per plane in pending_flips */ - if (atomic_read(&obj->pending_flip) & (1 << (16 + intel_plane->pipe))) - return -EBUSY; - } list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) atomic_pipe_commit(dev, s, intel_crtc->pipe); @@ -1582,8 +1546,6 @@ static int apply_nonblocking(struct drm_device *dev, struct intel_atomic_state * /* don't restore the old state in end() */ s->dirty = false; s->restore_state = false; - - return 0; } static int alloc_flip_data(struct drm_device *dev, struct intel_atomic_state *s) @@ -1695,12 +1657,7 @@ static int intel_atomic_commit(struct drm_device *dev, void *state) /* try to apply in a non blocking manner */ if (s->flags & DRM_MODE_ATOMIC_NONBLOCK) { - ret = apply_nonblocking(dev, s); - if (ret) { - unpin_cursors(dev, s); - unpin_fbs(dev, s); - return ret; - } + apply_nonblocking(dev, s); } else { /* apply in a blocking manner */ ret = apply_config(dev, s); @@ -1823,7 +1780,6 @@ static void intel_flip_complete(struct drm_flip *flip) struct intel_flip *intel_flip = container_of(flip, struct intel_flip, base); struct drm_device *dev = intel_flip->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = intel_flip->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; @@ -1841,18 +1797,6 @@ static void intel_flip_complete(struct drm_flip *flip) if (intel_flip->vblank_ref) drm_vblank_put(dev, pipe); - - /* Possibly allow rendering to old_bo again */ - if (intel_flip->old_bo) { - if (intel_flip->plane) { - struct intel_plane *intel_plane = to_intel_plane(intel_flip->plane); - atomic_clear_mask(1 << (16 + intel_plane->pipe), &intel_flip->old_bo->pending_flip.counter); - } else - atomic_clear_mask(1 << intel_crtc->plane, &intel_flip->old_bo->pending_flip.counter); - - if (atomic_read(&intel_flip->old_bo->pending_flip) == 0) - wake_up(&dev_priv->pending_flip_queue); - } } static void intel_flip_finish(struct drm_flip *flip) @@ -2193,13 +2137,6 @@ static void atomic_pipe_commit(struct drm_device *dev, mutex_lock(&dev->struct_mutex); drm_gem_object_reference(&intel_flip->old_bo->base); mutex_unlock(&dev->struct_mutex); - - /* -* Block clients from rendering to the new back buffer until -* the flip occurs and the object is
[Intel-gfx] [PATCH 49/81] drm: Move standard crtc/plane prop handling to drm_crtc.c
From: Ville Syrjälä Move some of the property code to drm_crtc.c since it should be shared by everyone. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc.c | 235 +++ drivers/gpu/drm/i915/intel_atomic.c | 256 -- drivers/gpu/drm/i915/intel_display.c | 29 3 files changed, 264 insertions(+), 256 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9d8738f..527b35b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4397,3 +4397,238 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, return ret; } + +static void drm_crtc_update_connector_ids_property(struct drm_crtc *crtc) +{ + struct drm_mode_config *config = &crtc->dev->mode_config; + struct drm_connector *connector; + uint64_t value = 0; + int i = 0; + uint32_t connector_ids[config->num_connector]; + + list_for_each_entry(connector, &config->connector_list, head) { + if (connector->encoder && connector->encoder->crtc == crtc) + connector_ids[i++] = connector->base.id; + } + + if (i) { + drm_property_blob_replace_data(crtc->connector_ids_blob, + i * sizeof connector_ids[0], connector_ids); + value = crtc->connector_ids_blob->base.id; + } else + drm_property_blob_replace_data(crtc->connector_ids_blob, 0, NULL); + + drm_object_property_set_value(&crtc->base, config->connector_ids_prop, value); +} + +static void drm_crtc_update_mode_property(struct drm_crtc *crtc) +{ + struct drm_mode_config *config = &crtc->dev->mode_config; + uint64_t value = 0; + + if (crtc->enabled) { + struct drm_mode_modeinfo umode; + + drm_crtc_convert_to_umode(&umode, &crtc->mode); + drm_property_blob_replace_data(crtc->mode_blob, sizeof umode, &umode); + value = crtc->mode_blob->base.id; + } else + drm_property_blob_replace_data(crtc->mode_blob, 0, NULL); + + drm_object_property_set_value(&crtc->base, config->mode_prop, value); +} + +void drm_crtc_update_properties(struct drm_crtc *crtc) +{ + struct drm_mode_object *obj = &crtc->base; + struct drm_mode_config *config = &crtc->dev->mode_config; + + drm_object_property_set_value(obj, config->src_x_prop, crtc->x); + drm_object_property_set_value(obj, config->src_y_prop, crtc->y); + drm_object_property_set_value(obj, config->fb_id_prop, crtc->fb ? crtc->fb->base.id : 0); + + drm_crtc_update_mode_property(crtc); + drm_crtc_update_connector_ids_property(crtc); +} +EXPORT_SYMBOL(drm_crtc_update_properties); + +void drm_plane_update_properties(struct drm_plane *plane) +{ + struct drm_mode_object *obj = &plane->base; + struct drm_mode_config *config = &plane->dev->mode_config; + + drm_object_property_set_value(obj, config->src_x_prop, plane->src_x); + drm_object_property_set_value(obj, config->src_y_prop, plane->src_y); + drm_object_property_set_value(obj, config->src_w_prop, plane->src_w); + drm_object_property_set_value(obj, config->src_h_prop, plane->src_h); + + drm_object_property_set_value(obj, config->crtc_x_prop, plane->crtc_x); + drm_object_property_set_value(obj, config->crtc_y_prop, plane->crtc_y); + drm_object_property_set_value(obj, config->crtc_w_prop, plane->crtc_w); + drm_object_property_set_value(obj, config->crtc_h_prop, plane->crtc_h); + + drm_object_property_set_value(obj, config->fb_id_prop, plane->fb ? plane->fb->base.id : 0); + drm_object_property_set_value(obj, config->crtc_id_prop, plane->crtc ? plane->crtc->base.id : 0); +} +EXPORT_SYMBOL(drm_plane_update_properties); + +int drm_crtc_create_blobs(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + + crtc->mode_blob = drm_property_create_blob(dev, 0, sizeof(struct drm_mode_modeinfo), NULL); + if (!crtc->mode_blob) + return -ENOMEM; + + crtc->connector_ids_blob = drm_property_create_blob(dev, 0, dev->mode_config.num_connector * sizeof(uint32_t), NULL); + if (!crtc->connector_ids_blob) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL(drm_crtc_create_blobs); + +void drm_crtc_destroy_blobs(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + + drm_property_destroy_blob(dev, crtc->mode_blob); + drm_property_destroy_blob(dev, crtc->connector_ids_blob); +} +EXPORT_SYMBOL(drm_crtc_destroy_blobs); + +static void drm_property_destroy_null(struct drm_device *dev, struct drm_property **prop) +{ + drm_property_destroy(dev, *prop); + *prop = NULL; +} + +void drm_mode_destroy_properties(struct drm_device *dev) +{ + struct drm_mode_config *config = &dev->mode_config; + + drm_property_destroy
[Intel-gfx] [PATCH 50/81] drm/i915: Use intel_best_encoder() directly
From: Ville Syrjälä All connectors use intel_best_encoder() as their best_encoder() func, so just call it directly w/o the indirection. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 10 ++ 1 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 6dd07fb..e58ec3f 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -152,8 +152,6 @@ static int process_connectors(struct intel_crtc_state *s, const uint32_t *ids, i int i; for (i = 0; i < count_ids; i++) { - struct drm_encoder *encoder; - const struct drm_connector_helper_funcs *connector_funcs; struct drm_mode_object *obj; int j; @@ -169,9 +167,8 @@ static int process_connectors(struct intel_crtc_state *s, const uint32_t *ids, i } connector = obj_to_connector(obj); - connector_funcs = connector->helper_private; - encoder = connector_funcs->best_encoder(connector); + encoder = intel_best_encoder(connector); if (!drm_encoder_crtc_ok(encoder, crtc)) return -EINVAL; @@ -180,9 +177,6 @@ static int process_connectors(struct intel_crtc_state *s, const uint32_t *ids, i } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - const struct drm_connector_helper_funcs *connector_funcs = - connector->helper_private; - for (i = 0; i < count_ids; i++) { if (connector == connectors[i]) break; @@ -196,7 +190,7 @@ static int process_connectors(struct intel_crtc_state *s, const uint32_t *ids, i continue; } - encoder = connector_funcs->best_encoder(connector); + encoder = intel_best_encoder(connector); connector->encoder = encoder; encoder->crtc = crtc; -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 46/81] drm_crtc_helper: Update standard crtc properties after modeset
From: Ville Syrjälä Keep the new CRTC properties when doing modeset through the legacy code paths. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_crtc_helper.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 30eb557..19444cd 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -782,6 +782,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) kfree(save_connectors); kfree(save_encoders); kfree(save_crtcs); + + /* changes in one CRTC can affect the others */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_crtc_update_properties(crtc); + return 0; fail: @@ -810,6 +815,11 @@ fail: kfree(save_connectors); kfree(save_encoders); kfree(save_crtcs); + + /* changes in one CRTC can affect the others */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_crtc_update_properties(crtc); + return ret; } EXPORT_SYMBOL(drm_crtc_helper_set_config); -- 1.7.8.6 ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx