From fb85ac4da8d202f89e0635e4ac2ac680d662be98 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 27 May 2013 20:19:58 +0300 Subject: drm: Drop all the stub gamma_get, gamma_set, load_lut functions from drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many of the drivers didn't implement palette/gamma handling, but were forced to provide stubs for the hooks to avoid drm_fb_helper from oopsing. Now that the hooks are optional, we can eliminate all the stubs. Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 13 ------------- drivers/gpu/drm/qxl/qxl_fb.c | 4 ---- 2 files changed, 17 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 823d29e926ec..5a6bfa22c5a7 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -222,12 +222,6 @@ static int qxl_add_common_modes(struct drm_connector *connector) return i - 1; } -static void qxl_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t start, uint32_t size) -{ - /* TODO */ -} - static void qxl_crtc_destroy(struct drm_crtc *crtc) { struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc); @@ -399,7 +393,6 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc, static const struct drm_crtc_funcs qxl_crtc_funcs = { .cursor_set = qxl_crtc_cursor_set, .cursor_move = qxl_crtc_cursor_move, - .gamma_set = qxl_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = qxl_crtc_destroy, }; @@ -619,18 +612,12 @@ static void qxl_crtc_commit(struct drm_crtc *crtc) DRM_DEBUG("\n"); } -static void qxl_crtc_load_lut(struct drm_crtc *crtc) -{ - DRM_DEBUG("\n"); -} - static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { .dpms = qxl_crtc_dpms, .mode_fixup = qxl_crtc_mode_fixup, .mode_set = qxl_crtc_mode_set, .prepare = qxl_crtc_prepare, .commit = qxl_crtc_commit, - .load_lut = qxl_crtc_load_lut, }; static int qdev_crtc_init(struct drm_device *dev, int num_crtc) diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index b3c51275df5c..4b955b04ce1e 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -520,10 +520,6 @@ static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev) } static struct drm_fb_helper_funcs qxl_fb_helper_funcs = { - /* TODO - .gamma_set = qxl_crtc_fb_gamma_set, - .gamma_get = qxl_crtc_fb_gamma_get, - */ .fb_probe = qxl_fb_find_or_create_single, }; -- cgit v1.2.3 From c0a608023006c5bc3512a374bb84a224a399786b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 20 Jun 2013 11:48:53 +1000 Subject: drm/qxl: add support for cursor hotspot. This uses the cursor hotspot info from userspace and passes it to the qxl hw layer. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 5a6bfa22c5a7..686a937675cb 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -249,11 +249,11 @@ qxl_hide_cursor(struct qxl_device *qdev) qxl_release_unreserve(qdev, release); } -static int qxl_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, int32_t hot_x, int32_t hot_y) { struct drm_device *dev = crtc->dev; struct qxl_device *qdev = dev->dev_private; @@ -309,8 +309,8 @@ static int qxl_crtc_cursor_set(struct drm_crtc *crtc, cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; cursor->header.width = 64; cursor->header.height = 64; - cursor->header.hot_spot_x = 0; - cursor->header.hot_spot_y = 0; + cursor->header.hot_spot_x = hot_x; + cursor->header.hot_spot_y = hot_y; cursor->data_size = size; cursor->chunk.next_chunk = 0; cursor->chunk.prev_chunk = 0; @@ -391,7 +391,7 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc, static const struct drm_crtc_funcs qxl_crtc_funcs = { - .cursor_set = qxl_crtc_cursor_set, + .cursor_set2 = qxl_crtc_cursor_set2, .cursor_move = qxl_crtc_cursor_move, .set_config = drm_crtc_helper_set_config, .destroy = qxl_crtc_destroy, -- cgit v1.2.3 From 5e338405119a80aa59e811626739122d1c15045d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 27 Jun 2013 13:48:19 +0200 Subject: drm/ttm: convert to the reservation api Now that the code is compatible in semantics, flip the switch. Use ww_mutex instead of the homegrown implementation. ww_mutex uses -EDEADLK to signal that the caller has to back off, and -EALREADY to indicate this buffer is already held by the caller. ttm used -EAGAIN and -EDEADLK for those, respectively. So some changes were needed to handle this correctly. Signed-off-by: Maarten Lankhorst Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/qxl/qxl_object.h | 5 - drivers/gpu/drm/ttm/ttm_bo.c | 190 +++++++++------------------------ drivers/gpu/drm/ttm/ttm_bo_util.c | 6 +- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 43 +++----- include/drm/ttm/ttm_bo_api.h | 25 ++--- include/drm/ttm/ttm_execbuf_util.h | 1 - 7 files changed, 79 insertions(+), 193 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index e35d4688711c..2b2077d1e2f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -368,7 +368,7 @@ retry: ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket); if (ret) { validate_fini_no_ticket(op, NULL); - if (unlikely(ret == -EAGAIN)) { + if (unlikely(ret == -EDEADLK)) { ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, &op->ticket); if (!ret) diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index b4fd89fbd8b7..ee7ad79ce781 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -57,11 +57,6 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo) return bo->tbo.num_pages << PAGE_SHIFT; } -static inline bool qxl_bo_is_reserved(struct qxl_bo *bo) -{ - return !!atomic_read(&bo->tbo.reserved); -} - static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo) { return bo->tbo.addr_space_offset; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index b912375b9c18..5f9fe8044afc 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -150,6 +150,9 @@ static void ttm_bo_release_list(struct kref *list_kref) if (bo->ttm) ttm_tt_destroy(bo->ttm); atomic_dec(&bo->glob->bo_count); + if (bo->resv == &bo->ttm_resv) + reservation_object_fini(&bo->ttm_resv); + if (bo->destroy) bo->destroy(bo); else { @@ -158,18 +161,6 @@ static void ttm_bo_release_list(struct kref *list_kref) ttm_mem_global_free(bdev->glob->mem_glob, acc_size); } -static int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, - bool interruptible) -{ - if (interruptible) { - return wait_event_interruptible(bo->event_queue, - !ttm_bo_is_reserved(bo)); - } else { - wait_event(bo->event_queue, !ttm_bo_is_reserved(bo)); - return 0; - } -} - void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; @@ -218,65 +209,27 @@ int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, bool no_wait, bool use_ticket, struct ww_acquire_ctx *ticket) { - int ret; + int ret = 0; - while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) { - /** - * Deadlock avoidance for multi-bo reserving. - */ - if (use_ticket && bo->seq_valid) { - /** - * We've already reserved this one. - */ - if (unlikely(ticket->stamp == bo->val_seq)) - return -EDEADLK; - /** - * Already reserved by a thread that will not back - * off for us. We need to back off. - */ - if (unlikely(ticket->stamp - bo->val_seq <= LONG_MAX)) - return -EAGAIN; - } + if (no_wait) { + bool success; - if (no_wait) + /* not valid any more, fix your locking! */ + if (WARN_ON(ticket)) return -EBUSY; - ret = ttm_bo_wait_unreserved(bo, interruptible); - - if (unlikely(ret)) - return ret; - } - - if (use_ticket) { - bool wake_up = false; - - /** - * Wake up waiters that may need to recheck for deadlock, - * if we decreased the sequence number. - */ - if (unlikely((bo->val_seq - ticket->stamp <= LONG_MAX) - || !bo->seq_valid)) - wake_up = true; - - /* - * In the worst case with memory ordering these values can be - * seen in the wrong order. However since we call wake_up_all - * in that case, this will hopefully not pose a problem, - * and the worst case would only cause someone to accidentally - * hit -EAGAIN in ttm_bo_reserve when they see old value of - * val_seq. However this would only happen if seq_valid was - * written before val_seq was, and just means some slightly - * increased cpu usage - */ - bo->val_seq = ticket->stamp; - bo->seq_valid = true; - if (wake_up) - wake_up_all(&bo->event_queue); - } else { - bo->seq_valid = false; + success = ww_mutex_trylock(&bo->resv->lock); + return success ? 0 : -EBUSY; } - return 0; + if (interruptible) + ret = ww_mutex_lock_interruptible(&bo->resv->lock, + ticket); + else + ret = ww_mutex_lock(&bo->resv->lock, ticket); + if (ret == -EINTR) + return -ERESTARTSYS; + return ret; } EXPORT_SYMBOL(ttm_bo_reserve); @@ -313,50 +266,27 @@ int ttm_bo_reserve(struct ttm_buffer_object *bo, return ret; } -int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo, - bool interruptible, - struct ww_acquire_ctx *ticket) -{ - bool wake_up = false; - int ret; - - while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) { - WARN_ON(bo->seq_valid && ticket->stamp == bo->val_seq); - - ret = ttm_bo_wait_unreserved(bo, interruptible); - - if (unlikely(ret)) - return ret; - } - - if (bo->val_seq - ticket->stamp < LONG_MAX || !bo->seq_valid) - wake_up = true; - - /** - * Wake up waiters that may need to recheck for deadlock, - * if we decreased the sequence number. - */ - bo->val_seq = ticket->stamp; - bo->seq_valid = true; - if (wake_up) - wake_up_all(&bo->event_queue); - - return 0; -} - int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, bool interruptible, struct ww_acquire_ctx *ticket) { struct ttm_bo_global *glob = bo->glob; - int put_count, ret; + int put_count = 0; + int ret = 0; + + if (interruptible) + ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, + ticket); + else + ww_mutex_lock_slow(&bo->resv->lock, ticket); - ret = ttm_bo_reserve_slowpath_nolru(bo, interruptible, ticket); - if (likely(!ret)) { + if (likely(ret == 0)) { spin_lock(&glob->lru_lock); put_count = ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); ttm_bo_list_ref_sub(bo, put_count, true); - } + } else if (ret == -EINTR) + ret = -ERESTARTSYS; + return ret; } EXPORT_SYMBOL(ttm_bo_reserve_slowpath); @@ -364,8 +294,7 @@ EXPORT_SYMBOL(ttm_bo_reserve_slowpath); void ttm_bo_unreserve_ticket_locked(struct ttm_buffer_object *bo, struct ww_acquire_ctx *ticket) { ttm_bo_add_to_lru(bo); - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ww_mutex_unlock(&bo->resv->lock); } void ttm_bo_unreserve(struct ttm_buffer_object *bo) @@ -558,17 +487,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) } ttm_bo_mem_put(bo, &bo->mem); - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); - - /* - * Since the final reference to this bo may not be dropped by - * the current task we have to put a memory barrier here to make - * sure the changes done in this function are always visible. - * - * This function only needs protection against the final kref_put. - */ - smp_mb__before_atomic_dec(); + ww_mutex_unlock (&bo->resv->lock); } static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) @@ -600,10 +519,8 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) sync_obj = driver->sync_obj_ref(bo->sync_obj); spin_unlock(&bdev->fence_lock); - if (!ret) { - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); - } + if (!ret) + ww_mutex_unlock(&bo->resv->lock); kref_get(&bo->list_kref); list_add_tail(&bo->ddestroy, &bdev->ddestroy); @@ -653,8 +570,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, sync_obj = driver->sync_obj_ref(bo->sync_obj); spin_unlock(&bdev->fence_lock); - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ww_mutex_unlock(&bo->resv->lock); spin_unlock(&glob->lru_lock); ret = driver->sync_obj_wait(sync_obj, false, interruptible); @@ -692,8 +608,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, spin_unlock(&bdev->fence_lock); if (ret || unlikely(list_empty(&bo->ddestroy))) { - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ww_mutex_unlock(&bo->resv->lock); spin_unlock(&glob->lru_lock); return ret; } @@ -1253,6 +1168,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, int ret = 0; unsigned long num_pages; struct ttm_mem_global *mem_glob = bdev->glob->mem_glob; + bool locked; ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false); if (ret) { @@ -1279,8 +1195,6 @@ int ttm_bo_init(struct ttm_bo_device *bdev, kref_init(&bo->kref); kref_init(&bo->list_kref); atomic_set(&bo->cpu_writers, 0); - atomic_set(&bo->reserved, 1); - init_waitqueue_head(&bo->event_queue); INIT_LIST_HEAD(&bo->lru); INIT_LIST_HEAD(&bo->ddestroy); INIT_LIST_HEAD(&bo->swap); @@ -1298,37 +1212,34 @@ int ttm_bo_init(struct ttm_bo_device *bdev, bo->mem.bus.io_reserved_count = 0; bo->priv_flags = 0; bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); - bo->seq_valid = false; bo->persistent_swap_storage = persistent_swap_storage; bo->acc_size = acc_size; bo->sg = sg; + bo->resv = &bo->ttm_resv; + reservation_object_init(bo->resv); atomic_inc(&bo->glob->bo_count); ret = ttm_bo_check_placement(bo, placement); - if (unlikely(ret != 0)) - goto out_err; /* * For ttm_bo_type_device buffers, allocate * address space from the device. */ - if (bo->type == ttm_bo_type_device || - bo->type == ttm_bo_type_sg) { + if (likely(!ret) && + (bo->type == ttm_bo_type_device || + bo->type == ttm_bo_type_sg)) ret = ttm_bo_setup_vm(bo); - if (ret) - goto out_err; - } - ret = ttm_bo_validate(bo, placement, interruptible, false); - if (ret) - goto out_err; + locked = ww_mutex_trylock(&bo->resv->lock); + WARN_ON(!locked); - ttm_bo_unreserve(bo); - return 0; + if (likely(!ret)) + ret = ttm_bo_validate(bo, placement, interruptible, false); -out_err: ttm_bo_unreserve(bo); - ttm_bo_unref(&bo); + + if (unlikely(ret)) + ttm_bo_unref(&bo); return ret; } @@ -1941,8 +1852,7 @@ out: * already swapped buffer. */ - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ww_mutex_unlock(&bo->resv->lock); kref_put(&bo->list_kref, ttm_bo_release_list); return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index af894584dd90..319cf4127c5b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -433,6 +433,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, struct ttm_buffer_object *fbo; struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_driver *driver = bdev->driver; + int ret; fbo = kmalloc(sizeof(*fbo), GFP_KERNEL); if (!fbo) @@ -445,7 +446,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, * TODO: Explicit member copy would probably be better here. */ - init_waitqueue_head(&fbo->event_queue); INIT_LIST_HEAD(&fbo->ddestroy); INIT_LIST_HEAD(&fbo->lru); INIT_LIST_HEAD(&fbo->swap); @@ -463,6 +463,10 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; fbo->acc_size = 0; + fbo->resv = &fbo->ttm_resv; + reservation_object_init(fbo->resv); + ret = ww_mutex_trylock(&fbo->resv->lock); + WARN_ON(!ret); *new_obj = fbo; return 0; diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index efcb734e5543..7392da557be2 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -48,8 +48,7 @@ static void ttm_eu_backoff_reservation_locked(struct list_head *list, entry->removed = false; } else { - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ww_mutex_unlock(&bo->resv->lock); } } } @@ -134,8 +133,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, glob = entry->bo->glob; ww_acquire_init(ticket, &reservation_ww_class); - spin_lock(&glob->lru_lock); - retry: list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; @@ -144,42 +141,34 @@ retry: if (entry->reserved) continue; - ret = ttm_bo_reserve_nolru(bo, true, true, true, ticket); - switch (ret) { - case 0: - break; - case -EBUSY: - ttm_eu_del_from_lru_locked(list); - spin_unlock(&glob->lru_lock); - ret = ttm_bo_reserve_nolru(bo, true, false, - true, ticket); - spin_lock(&glob->lru_lock); - - if (!ret) - break; - if (unlikely(ret != -EAGAIN)) - goto err; + ret = ttm_bo_reserve_nolru(bo, true, false, true, ticket); - /* fallthrough */ - case -EAGAIN: + if (ret == -EDEADLK) { + /* uh oh, we lost out, drop every reservation and try + * to only reserve this buffer, then start over if + * this succeeds. + */ + spin_lock(&glob->lru_lock); ttm_eu_backoff_reservation_locked(list, ticket); spin_unlock(&glob->lru_lock); ttm_eu_list_ref_sub(list); - ret = ttm_bo_reserve_slowpath_nolru(bo, true, ticket); - if (unlikely(ret != 0)) + ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, + ticket); + if (unlikely(ret != 0)) { + if (ret == -EINTR) + ret = -ERESTARTSYS; goto err_fini; + } - spin_lock(&glob->lru_lock); entry->reserved = true; if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { ret = -EBUSY; goto err; } goto retry; - default: + } else if (ret) goto err; - } entry->reserved = true; if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { @@ -189,12 +178,14 @@ retry: } ww_acquire_done(ticket); + spin_lock(&glob->lru_lock); ttm_eu_del_from_lru_locked(list); spin_unlock(&glob->lru_lock); ttm_eu_list_ref_sub(list); return 0; err: + spin_lock(&glob->lru_lock); ttm_eu_backoff_reservation_locked(list, ticket); spin_unlock(&glob->lru_lock); ttm_eu_list_ref_sub(list); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 0a992b016fe9..31ad860c10cd 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -39,6 +39,7 @@ #include #include #include +#include struct ttm_bo_device; @@ -153,7 +154,6 @@ struct ttm_tt; * Lru lists may keep one refcount, the delayed delete list, and kref != 0 * keeps one refcount. When this refcount reaches zero, * the object is destroyed. - * @event_queue: Queue for processes waiting on buffer object status change. * @mem: structure describing current placement. * @persistent_swap_storage: Usually the swap storage is deleted for buffers * pinned in physical memory. If this behaviour is not desired, this member @@ -164,12 +164,6 @@ struct ttm_tt; * @lru: List head for the lru list. * @ddestroy: List head for the delayed destroy list. * @swap: List head for swap LRU list. - * @val_seq: Sequence of the validation holding the @reserved lock. - * Used to avoid starvation when many processes compete to validate the - * buffer. This member is protected by the bo_device::lru_lock. - * @seq_valid: The value of @val_seq is valid. This value is protected by - * the bo_device::lru_lock. - * @reserved: Deadlock-free lock used for synchronization state transitions. * @sync_obj: Pointer to a synchronization object. * @priv_flags: Flags describing buffer object internal state. * @vm_rb: Rb node for the vm rb tree. @@ -209,10 +203,9 @@ struct ttm_buffer_object { struct kref kref; struct kref list_kref; - wait_queue_head_t event_queue; /** - * Members protected by the bo::reserved lock. + * Members protected by the bo::resv::reserved lock. */ struct ttm_mem_reg mem; @@ -234,15 +227,6 @@ struct ttm_buffer_object { struct list_head ddestroy; struct list_head swap; struct list_head io_reserve_lru; - unsigned long val_seq; - bool seq_valid; - - /** - * Members protected by the bdev::lru_lock - * only when written to. - */ - - atomic_t reserved; /** * Members protected by struct buffer_object_device::fence_lock @@ -272,6 +256,9 @@ struct ttm_buffer_object { uint32_t cur_placement; struct sg_table *sg; + + struct reservation_object *resv; + struct reservation_object ttm_resv; }; /** @@ -736,7 +723,7 @@ extern void ttm_bo_swapout_all(struct ttm_bo_device *bdev); */ static inline bool ttm_bo_is_reserved(struct ttm_buffer_object *bo) { - return atomic_read(&bo->reserved); + return ww_mutex_is_locked(&bo->resv->lock); } #endif diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index ba71ef91f4d5..ec8a1d306510 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -33,7 +33,6 @@ #include #include -#include /** * struct ttm_validate_buffer -- cgit v1.2.3 From 5b8788c1740fae8416e7e045301d99676d20bd64 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 1 Jul 2013 14:14:38 +1000 Subject: drm/qxl: make dynamic resizing work properly. qxl has a feature to allow the userspace driver do arbitrary resizes when the viewer resizes, this fixes it by removing unnecessary code from the kernel side. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 58 ++------------------------------------- 1 file changed, 3 insertions(+), 55 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 686a937675cb..df5ca7e72e67 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -30,55 +30,6 @@ #include "qxl_object.h" #include "drm_crtc_helper.h" -static void qxl_crtc_set_to_mode(struct qxl_device *qdev, - struct drm_connector *connector, - struct qxl_head *head) -{ - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode, *t; - int width = head->width; - int height = head->height; - - if (width < 320 || height < 240) { - qxl_io_log(qdev, "%s: bad head: %dx%d", width, height); - width = 1024; - height = 768; - } - if (width * height * 4 > 16*1024*1024) { - width = 1024; - height = 768; - } - /* TODO: go over regular modes and removed preferred? */ - list_for_each_entry_safe(mode, t, &connector->probed_modes, head) - drm_mode_remove(connector, mode); - mode = drm_cvt_mode(dev, width, height, 60, false, false, false); - mode->type |= DRM_MODE_TYPE_PREFERRED; - mode->status = MODE_OK; - drm_mode_probed_add(connector, mode); - qxl_io_log(qdev, "%s: %d x %d\n", __func__, width, height); -} - -void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev) -{ - struct drm_connector *connector; - int i; - struct drm_device *dev = qdev->ddev; - - i = 0; - qxl_io_log(qdev, "%s: %d, %d\n", __func__, - dev->mode_config.num_connector, - qdev->monitors_config->count); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (i > qdev->monitors_config->count) { - /* crtc will be reported as disabled */ - continue; - } - qxl_crtc_set_to_mode(qdev, connector, - &qdev->monitors_config->heads[i]); - ++i; - } -} - void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) { if (qdev->client_monitors_config && @@ -117,8 +68,8 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) return 1; } if (num_monitors > qdev->monitors_config->max_allowed) { - DRM_INFO("client monitors list will be truncated: %d < %d\n", - qdev->monitors_config->max_allowed, num_monitors); + DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n", + qdev->monitors_config->max_allowed, num_monitors); num_monitors = qdev->monitors_config->max_allowed; } else { num_monitors = qdev->rom->client_monitors_config.count; @@ -142,7 +93,7 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) client_head->surface_id = head->surface_id = 0; client_head->id = head->id = i; client_head->flags = head->flags = 0; - QXL_DEBUG(qdev, "read %dx%d+%d+%d\n", head->width, head->height, + DRM_DEBUG_KMS("read %dx%d+%d+%d\n", head->width, head->height, head->x, head->y); } return 0; @@ -155,9 +106,6 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev) qxl_io_log(qdev, "failed crc check for client_monitors_config," " retrying\n"); } - qxl_crtc_set_from_monitors_config(qdev); - /* fire off a uevent and let userspace tell us what to do */ - qxl_io_log(qdev, "calling drm_sysfs_hotplug_event\n"); drm_sysfs_hotplug_event(qdev->ddev); } -- cgit v1.2.3 From 07f8d9bdb235836d0a255d20f387bc3afa99180f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 2 Jul 2013 06:37:13 +0100 Subject: drm/qxl: add support for > 1 output This adds support for a default of 4 heads, with a command line parameter to change the default number. It also overhauls the modesetting code to handle this case properly, and send the correct things to the hardware at the right time. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_cmd.c | 8 +-- drivers/gpu/drm/qxl/qxl_display.c | 121 +++++++++++++++++++++++--------------- drivers/gpu/drm/qxl/qxl_drv.c | 4 ++ drivers/gpu/drm/qxl/qxl_drv.h | 8 +-- drivers/gpu/drm/qxl/qxl_fb.c | 2 +- 5 files changed, 85 insertions(+), 58 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index f86771481317..92cf1afd60e5 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -375,8 +375,8 @@ void qxl_io_destroy_primary(struct qxl_device *qdev) wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); } -void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, - unsigned height, unsigned offset, struct qxl_bo *bo) +void qxl_io_create_primary(struct qxl_device *qdev, + unsigned offset, struct qxl_bo *bo) { struct qxl_surface_create *create; @@ -384,8 +384,8 @@ void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, qdev->ram_header); create = &qdev->ram_header->create_surface; create->format = bo->surf.format; - create->width = width; - create->height = height; + create->width = bo->surf.width; + create->height = bo->surf.height; create->stride = bo->surf.stride; create->mem = qxl_bo_physical_address(qdev, bo, offset); diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index df5ca7e72e67..d3b92618246e 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -30,6 +30,11 @@ #include "qxl_object.h" #include "drm_crtc_helper.h" +static bool qxl_head_enabled(struct qxl_head *head) +{ + return head->width && head->height; +} + void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) { if (qdev->client_monitors_config && @@ -57,7 +62,6 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) int num_monitors; uint32_t crc; - BUG_ON(!qdev->monitors_config); num_monitors = qdev->rom->client_monitors_config.count; crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config, sizeof(qdev->rom->client_monitors_config)); @@ -83,18 +87,15 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) &qdev->rom->client_monitors_config.heads[i]; struct qxl_head *client_head = &qdev->client_monitors_config->heads[i]; - struct qxl_head *head = &qdev->monitors_config->heads[i]; - client_head->x = head->x = c_rect->left; - client_head->y = head->y = c_rect->top; - client_head->width = head->width = - c_rect->right - c_rect->left; - client_head->height = head->height = - c_rect->bottom - c_rect->top; - client_head->surface_id = head->surface_id = 0; - client_head->id = head->id = i; - client_head->flags = head->flags = 0; - DRM_DEBUG_KMS("read %dx%d+%d+%d\n", head->width, head->height, - head->x, head->y); + client_head->x = c_rect->left; + client_head->y = c_rect->top; + client_head->width = c_rect->right - c_rect->left; + client_head->height = c_rect->bottom - c_rect->top; + client_head->surface_id = 0; + client_head->id = i; + client_head->flags = 0; + DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head->width, client_head->height, + client_head->x, client_head->y); } return 0; } @@ -118,9 +119,9 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector) struct drm_display_mode *mode = NULL; struct qxl_head *head; - if (!qdev->monitors_config) + if (!qdev->client_monitors_config) return 0; - head = &qdev->monitors_config->heads[h]; + head = &qdev->client_monitors_config->heads[h]; mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false, false); @@ -447,7 +448,7 @@ qxl_send_monitors_config(struct qxl_device *qdev) for (i = 0 ; i < qdev->monitors_config->count ; ++i) { struct qxl_head *head = &qdev->monitors_config->heads[i]; - if (head->y > 8192 || head->y < head->x || + if (head->y > 8192 || head->x > 8192 || head->width > 8192 || head->height > 8192) { DRM_ERROR("head %d wrong: %dx%d+%d+%d\n", i, head->width, head->height, @@ -458,16 +459,19 @@ qxl_send_monitors_config(struct qxl_device *qdev) qxl_io_monitors_config(qdev); } -static void qxl_monitors_config_set_single(struct qxl_device *qdev, - unsigned x, unsigned y, - unsigned width, unsigned height) +static void qxl_monitors_config_set(struct qxl_device *qdev, + int index, + unsigned x, unsigned y, + unsigned width, unsigned height, + unsigned surf_id) { - DRM_DEBUG("%dx%d+%d+%d\n", width, height, x, y); - qdev->monitors_config->count = 1; - qdev->monitors_config->heads[0].x = x; - qdev->monitors_config->heads[0].y = y; - qdev->monitors_config->heads[0].width = width; - qdev->monitors_config->heads[0].height = height; + DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index, width, height, x, y); + qdev->monitors_config->heads[index].x = x; + qdev->monitors_config->heads[index].y = y; + qdev->monitors_config->heads[index].width = width; + qdev->monitors_config->heads[index].height = height; + qdev->monitors_config->heads[index].surface_id = surf_id; + } static int qxl_crtc_mode_set(struct drm_crtc *crtc, @@ -481,10 +485,11 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, struct qxl_mode *m = (void *)mode->private; struct qxl_framebuffer *qfb; struct qxl_bo *bo, *old_bo = NULL; + struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); uint32_t width, height, base_offset; bool recreate_primary = false; int ret; - + int surf_id; if (!crtc->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; @@ -508,7 +513,8 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, adjusted_mode->hdisplay, adjusted_mode->vdisplay); - recreate_primary = true; + if (qcrtc->index == 0) + recreate_primary = true; width = mode->hdisplay; height = mode->vdisplay; @@ -529,8 +535,11 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, "recreate primary: %dx%d (was %dx%d,%d,%d)\n", width, height, bo->surf.width, bo->surf.height, bo->surf.stride, bo->surf.format); - qxl_io_create_primary(qdev, width, height, base_offset, bo); + qxl_io_create_primary(qdev, base_offset, bo); bo->is_primary = true; + surf_id = 0; + } else { + surf_id = bo->surface_id; } if (old_bo && old_bo != bo) { @@ -540,11 +549,9 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, qxl_bo_unreserve(old_bo); } - if (qdev->monitors_config->count == 0) { - qxl_monitors_config_set_single(qdev, x, y, - mode->hdisplay, - mode->vdisplay); - } + qxl_monitors_config_set(qdev, qcrtc->index, x, y, + mode->hdisplay, + mode->vdisplay, surf_id); return 0; } @@ -560,15 +567,36 @@ static void qxl_crtc_commit(struct drm_crtc *crtc) DRM_DEBUG("\n"); } +static void qxl_crtc_disable(struct drm_crtc *crtc) +{ + struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct qxl_device *qdev = dev->dev_private; + if (crtc->fb) { + struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb); + struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj); + int ret; + ret = qxl_bo_reserve(bo, false); + qxl_bo_unpin(bo); + qxl_bo_unreserve(bo); + crtc->fb = NULL; + } + + qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0); + + qxl_send_monitors_config(qdev); +} + static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { .dpms = qxl_crtc_dpms, + .disable = qxl_crtc_disable, .mode_fixup = qxl_crtc_mode_fixup, .mode_set = qxl_crtc_mode_set, .prepare = qxl_crtc_prepare, .commit = qxl_crtc_commit, }; -static int qdev_crtc_init(struct drm_device *dev, int num_crtc) +static int qdev_crtc_init(struct drm_device *dev, int crtc_id) { struct qxl_crtc *qxl_crtc; @@ -577,7 +605,7 @@ static int qdev_crtc_init(struct drm_device *dev, int num_crtc) return -ENOMEM; drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs); - + qxl_crtc->index = crtc_id; drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256); drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs); return 0; @@ -605,18 +633,13 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev, struct drm_encoder *encoder) { int i; + struct qxl_output *output = drm_encoder_to_qxl_output(encoder); struct qxl_head *head; struct drm_display_mode *mode; BUG_ON(!encoder); /* TODO: ugly, do better */ - for (i = 0 ; (encoder->possible_crtcs != (1 << i)) && i < 32; ++i) - ; - if (encoder->possible_crtcs != (1 << i)) { - DRM_ERROR("encoder has wrong possible_crtcs: %x\n", - encoder->possible_crtcs); - return; - } + i = output->index; if (!qdev->monitors_config || qdev->monitors_config->max_allowed <= i) { DRM_ERROR( @@ -634,7 +657,6 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev, DRM_DEBUG("missing for multiple monitors: no head holes\n"); head = &qdev->monitors_config->heads[i]; head->id = i; - head->surface_id = 0; if (encoder->crtc->enabled) { mode = &encoder->crtc->mode; head->width = mode->hdisplay; @@ -649,8 +671,8 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev, head->x = 0; head->y = 0; } - DRM_DEBUG("setting head %d to +%d+%d %dx%d\n", - i, head->x, head->y, head->width, head->height); + DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n", + i, head->x, head->y, head->width, head->height, qdev->monitors_config->count); head->flags = 0; /* TODO - somewhere else to call this for multiple monitors * (config_commit?) */ @@ -745,8 +767,9 @@ static enum drm_connector_status qxl_conn_detect( /* The first monitor is always connected */ connected = (output->index == 0) || - (qdev->monitors_config && - qdev->monitors_config->count > output->index); + (qdev->client_monitors_config && + qdev->client_monitors_config->count > output->index && + qxl_head_enabled(&qdev->client_monitors_config->heads[output->index])); DRM_DEBUG("\n"); return connected ? connector_status_connected @@ -854,7 +877,7 @@ int qxl_modeset_init(struct qxl_device *qdev) int i; int ret; struct drm_gem_object *gobj; - int max_allowed = QXL_NUM_OUTPUTS; + int max_allowed = qxl_num_crtc; int monitors_config_size = sizeof(struct qxl_monitors_config) + max_allowed * sizeof(struct qxl_head); @@ -884,7 +907,7 @@ int qxl_modeset_init(struct qxl_device *qdev) qdev->ddev->mode_config.max_height = 8192; qdev->ddev->mode_config.fb_base = qdev->vram_base; - for (i = 0 ; i < QXL_NUM_OUTPUTS; ++i) { + for (i = 0 ; i < qxl_num_crtc; ++i) { qdev_crtc_init(qdev->ddev, i); qdev_output_init(qdev->ddev, i); } diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index aa291d8a98a2..00e57b76f4f5 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -47,10 +47,14 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { MODULE_DEVICE_TABLE(pci, pciidlist); static int qxl_modeset = -1; +int qxl_num_crtc = 4; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, qxl_modeset, int, 0400); +MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); +module_param_named(num_heads, qxl_num_crtc, int, 0400); + static struct drm_driver qxl_driver; static struct pci_driver qxl_pci_driver; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 43d06ab28a21..42ef0e2b5094 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -55,11 +55,10 @@ #define DRIVER_MINOR 1 #define DRIVER_PATCHLEVEL 0 -#define QXL_NUM_OUTPUTS 1 - #define QXL_DEBUGFS_MAX_COMPONENTS 32 extern int qxl_log_level; +extern int qxl_num_crtc; enum { QXL_INFO_LEVEL = 1, @@ -139,6 +138,7 @@ struct qxl_reloc_list { struct qxl_crtc { struct drm_crtc base; + int index; int cur_x; int cur_y; }; @@ -156,7 +156,7 @@ struct qxl_framebuffer { #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base) #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base) -#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, base) +#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc) #define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base) struct qxl_mman { @@ -435,7 +435,7 @@ void qxl_update_screen(struct qxl_device *qxl); /* qxl io operations (qxl_cmd.c) */ void qxl_io_create_primary(struct qxl_device *qdev, - unsigned width, unsigned height, unsigned offset, + unsigned offset, struct qxl_bo *bo); void qxl_io_destroy_primary(struct qxl_device *qdev); void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 4b955b04ce1e..c08e12886d6c 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -538,7 +538,7 @@ int qxl_fbdev_init(struct qxl_device *qdev) qfbdev->helper.funcs = &qxl_fb_helper_funcs; ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper, - 1 /* num_crtc - QXL supports just 1 */, + qxl_num_crtc /* num_crtc - QXL supports just 1 */, QXLFB_CONN_LIMIT); if (ret) { kfree(qfbdev); -- cgit v1.2.3 From c927215543eb8f67c2c0102db147c299189c9957 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 2 Jul 2013 10:44:50 +0100 Subject: drm/qxl: set time on drawables from userspace This just sets the qxl time on the drawables. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_ioctl.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index a4b71b25fa53..6ba49d9922f2 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -183,6 +183,12 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, /* TODO copy slow path code from i915 */ fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE)); unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size); + + { + struct qxl_drawable *draw = fb_cmd; + + draw->mm_time = qdev->rom->mm_clock; + } qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd); if (unwritten) { DRM_ERROR("got unwritten %d\n", unwritten); -- cgit v1.2.3 From 2bd6ce84e1b4799be1f328a165d0b8a4fdfd2141 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Jul 2013 14:46:46 +1000 Subject: qxl: split monitors_config object creation out. This splits the creation of the monitors config object out so we can re-use it across suspend/resume later. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 54 ++++++++++++++++++++++++++++++++++++--- drivers/gpu/drm/qxl/qxl_drv.h | 2 ++ 2 files changed, 52 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index d3b92618246e..61714fdfc782 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -872,16 +872,14 @@ static const struct drm_mode_config_funcs qxl_mode_funcs = { .fb_create = qxl_user_framebuffer_create, }; -int qxl_modeset_init(struct qxl_device *qdev) +int qxl_create_monitors_object(struct qxl_device *qdev) { - int i; int ret; struct drm_gem_object *gobj; int max_allowed = qxl_num_crtc; int monitors_config_size = sizeof(struct qxl_monitors_config) + - max_allowed * sizeof(struct qxl_head); + max_allowed * sizeof(struct qxl_head); - drm_mode_config_init(qdev->ddev); ret = qxl_gem_object_create(qdev, monitors_config_size, 0, QXL_GEM_DOMAIN_VRAM, false, false, NULL, &gobj); @@ -890,13 +888,59 @@ int qxl_modeset_init(struct qxl_device *qdev) return -ENOMEM; } qdev->monitors_config_bo = gem_to_qxl_bo(gobj); + + ret = qxl_bo_reserve(qdev->monitors_config_bo, false); + if (ret) + return ret; + + ret = qxl_bo_pin(qdev->monitors_config_bo, QXL_GEM_DOMAIN_VRAM, NULL); + if (ret) { + qxl_bo_unreserve(qdev->monitors_config_bo); + return ret; + } + + qxl_bo_unreserve(qdev->monitors_config_bo); + qxl_bo_kmap(qdev->monitors_config_bo, NULL); + qdev->monitors_config = qdev->monitors_config_bo->kptr; qdev->ram_header->monitors_config = qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0); memset(qdev->monitors_config, 0, monitors_config_size); qdev->monitors_config->max_allowed = max_allowed; + return 0; +} + +int qxl_destroy_monitors_object(struct qxl_device *qdev) +{ + int ret; + + qdev->monitors_config = NULL; + qdev->ram_header->monitors_config = 0; + + qxl_bo_kunmap(qdev->monitors_config_bo); + ret = qxl_bo_reserve(qdev->monitors_config_bo, false); + if (ret) + return ret; + + qxl_bo_unpin(qdev->monitors_config_bo); + qxl_bo_unreserve(qdev->monitors_config_bo); + + qxl_bo_unref(&qdev->monitors_config_bo); + return 0; +} + +int qxl_modeset_init(struct qxl_device *qdev) +{ + int i; + int ret; + + drm_mode_config_init(qdev->ddev); + + ret = qxl_create_monitors_object(qdev); + if (ret) + return ret; qdev->ddev->mode_config.funcs = (void *)&qxl_mode_funcs; @@ -924,6 +968,8 @@ int qxl_modeset_init(struct qxl_device *qdev) void qxl_modeset_fini(struct qxl_device *qdev) { qxl_fbdev_fini(qdev); + + qxl_destroy_monitors_object(qdev); if (qdev->mode_info.mode_config_initialized) { drm_mode_config_cleanup(qdev->ddev); qdev->mode_info.mode_config_initialized = false; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 42ef0e2b5094..6a929258fff9 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -374,6 +374,8 @@ qxl_framebuffer_init(struct drm_device *dev, struct drm_gem_object *obj); void qxl_display_read_client_monitors_config(struct qxl_device *qdev); void qxl_send_monitors_config(struct qxl_device *qdev); +int qxl_create_monitors_object(struct qxl_device *qdev); +int qxl_destroy_monitors_object(struct qxl_device *qdev); /* used by qxl_debugfs only */ void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev); -- cgit v1.2.3 From c9fdda2a2b7a8875db3eebd89e428aa760afb897 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Jul 2013 14:57:58 +1000 Subject: qxl: prepare memslot code for suspend/resume this splits out initing the hw memslots from the guest info, and creates an entrypoint for s/r to use. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_drv.h | 2 ++ drivers/gpu/drm/qxl/qxl_kms.c | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 6a929258fff9..056330e5fecf 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -331,6 +331,8 @@ void qxl_modeset_fini(struct qxl_device *qdev); int qxl_bo_init(struct qxl_device *qdev); void qxl_bo_fini(struct qxl_device *qdev); +void qxl_reinit_memslots(struct qxl_device *qdev); + struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, int element_size, int n_elements, diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index e27ce2a907cf..2c6f9219e9d9 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -72,21 +72,28 @@ static bool qxl_check_device(struct qxl_device *qdev) return true; } +static void setup_hw_slot(struct qxl_device *qdev, int slot_index, + struct qxl_memslot *slot) +{ + qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr; + qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr; + qxl_io_memslot_add(qdev, slot_index); +} + static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, unsigned long start_phys_addr, unsigned long end_phys_addr) { uint64_t high_bits; struct qxl_memslot *slot; uint8_t slot_index; - struct qxl_ram_header *ram_header = qdev->ram_header; slot_index = qdev->rom->slots_start + slot_index_offset; slot = &qdev->mem_slots[slot_index]; slot->start_phys_addr = start_phys_addr; slot->end_phys_addr = end_phys_addr; - ram_header->mem_slot.mem_start = slot->start_phys_addr; - ram_header->mem_slot.mem_end = slot->end_phys_addr; - qxl_io_memslot_add(qdev, slot_index); + + setup_hw_slot(qdev, slot_index, slot); + slot->generation = qdev->rom->slot_generation; high_bits = slot_index << qdev->slot_gen_bits; high_bits |= slot->generation; @@ -95,6 +102,12 @@ static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, return slot_index; } +void qxl_reinit_memslots(struct qxl_device *qdev) +{ + setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]); + setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]); +} + static void qxl_gc_work(struct work_struct *work) { struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); -- cgit v1.2.3 From 1e209117dbe00d3d87db1c5266f177eaa60451c8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Jul 2013 14:58:45 +1000 Subject: qxl: add ring prep code for s/r This prepare the ring code for s/r additions, the release ring will need reinitialising. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_cmd.c | 9 +++++++-- drivers/gpu/drm/qxl/qxl_drv.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 92cf1afd60e5..93c2f2cceb51 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -49,6 +49,11 @@ void qxl_ring_free(struct qxl_ring *ring) kfree(ring); } +void qxl_ring_init_hdr(struct qxl_ring *ring) +{ + ring->ring->header.notify_on_prod = ring->n_elements; +} + struct qxl_ring * qxl_ring_create(struct qxl_ring_header *header, int element_size, @@ -69,7 +74,7 @@ qxl_ring_create(struct qxl_ring_header *header, ring->prod_notify = prod_notify; ring->push_event = push_event; if (set_prod_notify) - header->notify_on_prod = ring->n_elements; + qxl_ring_init_hdr(ring); spin_lock_init(&ring->lock); return ring; } @@ -87,7 +92,7 @@ static int qxl_check_header(struct qxl_ring *ring) return ret; } -static int qxl_check_idle(struct qxl_ring *ring) +int qxl_check_idle(struct qxl_ring *ring) { int ret; struct qxl_ring_header *header = &(ring->ring->header); diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 056330e5fecf..aec9f1f9c814 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -340,6 +340,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, bool set_prod_notify, wait_queue_head_t *push_event); void qxl_ring_free(struct qxl_ring *ring); +void qxl_ring_init_hdr(struct qxl_ring *ring); +int qxl_check_idle(struct qxl_ring *ring); static inline void * qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical) -- cgit v1.2.3 From b86487a6b671ff7107fbf6d3ff10c2da970cd1c3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Jul 2013 14:59:34 +1000 Subject: qxl: add fb and ttm entry points for use by suspend/resume. This just ports some APIs like radeon uses to provide hooks for s/r to call. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_drv.h | 3 +++ drivers/gpu/drm/qxl/qxl_fb.c | 10 ++++++++++ drivers/gpu/drm/qxl/qxl_object.c | 5 +++++ 3 files changed, 18 insertions(+) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index aec9f1f9c814..70a67862673a 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -332,6 +332,7 @@ int qxl_bo_init(struct qxl_device *qdev); void qxl_bo_fini(struct qxl_device *qdev); void qxl_reinit_memslots(struct qxl_device *qdev); +int qxl_surf_evict(struct qxl_device *qdev); struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, int element_size, @@ -369,6 +370,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev); int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, struct drm_file *file_priv, uint32_t *handle); +void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state); /* qxl_display.c */ int @@ -534,6 +536,7 @@ irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS); /* qxl_fb.c */ int qxl_fb_init(struct qxl_device *qdev); +bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj); int qxl_debugfs_add_files(struct qxl_device *qdev, struct drm_info_list *files, diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index c08e12886d6c..76f39d88d684 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -560,4 +560,14 @@ void qxl_fbdev_fini(struct qxl_device *qdev) qdev->mode_info.qfbdev = NULL; } +void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state) +{ + fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state); +} +bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj) +{ + if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj)) + return true; + return false; +} diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index d9b12e7bc6e1..62a046e4a036 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -363,3 +363,8 @@ int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo) return ret; return 0; } + +int qxl_surf_evict(struct qxl_device *qdev) +{ + return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0); +} -- cgit v1.2.3 From d84300bf793471cc20c7553601c45d6f70dd2b1e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Jul 2013 15:02:33 +1000 Subject: qxl: add suspend/resume/hibernate support. This adds suspend/resume and hibernate support for the KMS driver. it evicts all the objects, turns off the outputs, and waits for the hw to go idle, On resume, it resets the memslots, rings, monitors object and forces modeset. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_drv.c | 134 ++++++++++++++++++++++++++++++++++++--- drivers/gpu/drm/qxl/qxl_drv.h | 1 + drivers/gpu/drm/qxl/qxl_object.c | 5 ++ 3 files changed, 132 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 00e57b76f4f5..df0b577a6608 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -33,8 +33,9 @@ #include "drmP.h" #include "drm/drm.h" - +#include "drm_crtc_helper.h" #include "qxl_drv.h" +#include "qxl_object.h" extern int qxl_max_ioctls; static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { @@ -77,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev) drm_put_dev(dev); } -static struct pci_driver qxl_pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - .probe = qxl_pci_probe, - .remove = qxl_pci_remove, -}; - static const struct file_operations qxl_fops = { .owner = THIS_MODULE, .open = drm_open, @@ -94,6 +88,130 @@ static const struct file_operations qxl_fops = { .mmap = qxl_mmap, }; +static int qxl_drm_freeze(struct drm_device *dev) +{ + struct pci_dev *pdev = dev->pdev; + struct qxl_device *qdev = dev->dev_private; + struct drm_crtc *crtc; + + drm_kms_helper_poll_disable(dev); + + console_lock(); + qxl_fbdev_set_suspend(qdev, 1); + console_unlock(); + + /* unpin the front buffers */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + if (crtc->enabled) + (*crtc_funcs->disable)(crtc); + } + + qxl_destroy_monitors_object(qdev); + qxl_surf_evict(qdev); + qxl_vram_evict(qdev); + + while (!qxl_check_idle(qdev->command_ring)); + while (!qxl_check_idle(qdev->release_ring)) + qxl_queue_garbage_collect(qdev, 1); + + pci_save_state(pdev); + + return 0; +} + +static int qxl_drm_resume(struct drm_device *dev, bool thaw) +{ + struct qxl_device *qdev = dev->dev_private; + + qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; + if (!thaw) { + qxl_reinit_memslots(qdev); + qxl_ring_init_hdr(qdev->release_ring); + } + + qxl_create_monitors_object(qdev); + drm_helper_resume_force_mode(dev); + + console_lock(); + qxl_fbdev_set_suspend(qdev, 0); + console_unlock(); + + drm_kms_helper_poll_enable(dev); + return 0; +} + +static int qxl_pm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int error; + + error = qxl_drm_freeze(drm_dev); + if (error) + return error; + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + return 0; +} + +static int qxl_pm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + if (pci_enable_device(pdev)) { + return -EIO; + } + + return qxl_drm_resume(drm_dev, false); +} + +static int qxl_pm_thaw(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return qxl_drm_resume(drm_dev, true); +} + +static int qxl_pm_freeze(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return qxl_drm_freeze(drm_dev); +} + +static int qxl_pm_restore(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct qxl_device *qdev = drm_dev->dev_private; + + qxl_io_reset(qdev); + return qxl_drm_resume(drm_dev, false); +} + +static const struct dev_pm_ops qxl_pm_ops = { + .suspend = qxl_pm_suspend, + .resume = qxl_pm_resume, + .freeze = qxl_pm_freeze, + .thaw = qxl_pm_thaw, + .poweroff = qxl_pm_freeze, + .restore = qxl_pm_restore, +}; +static struct pci_driver qxl_pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = qxl_pci_probe, + .remove = qxl_pci_remove, + .driver.pm = &qxl_pm_ops, +}; + static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 70a67862673a..aacb791464a3 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -333,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev); void qxl_reinit_memslots(struct qxl_device *qdev); int qxl_surf_evict(struct qxl_device *qdev); +int qxl_vram_evict(struct qxl_device *qdev); struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, int element_size, diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 62a046e4a036..1191fe7788c9 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -368,3 +368,8 @@ int qxl_surf_evict(struct qxl_device *qdev) { return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0); } + +int qxl_vram_evict(struct qxl_device *qdev) +{ + return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM); +} -- cgit v1.2.3 From 5ff91e442652ec33a648c3b9ae5025faaff1e813 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Jul 2013 10:20:33 +1000 Subject: qxl: use drm helper hotplug support This uses the helper to deal with hotplug so fbdev gets included. Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 4 +++- drivers/gpu/drm/qxl/qxl_kms.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/qxl') diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 61714fdfc782..f76f5dd7bfc4 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -107,7 +107,7 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev) qxl_io_log(qdev, "failed crc check for client_monitors_config," " retrying\n"); } - drm_sysfs_hotplug_event(qdev->ddev); + drm_helper_hpd_irq_event(qdev->ddev); } static int qxl_add_monitors_config_modes(struct drm_connector *connector) @@ -833,6 +833,8 @@ static int qdev_output_init(struct drm_device *dev, int num_output) drm_encoder_init(dev, &qxl_output->enc, &qxl_enc_funcs, DRM_MODE_ENCODER_VIRTUAL); + /* we get HPD via client monitors config */ + connector->polled = DRM_CONNECTOR_POLL_HPD; encoder->possible_crtcs = 1 << num_output; drm_mode_connector_attach_encoder(&qxl_output->base, &qxl_output->enc); diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 2c6f9219e9d9..9e8da9ee9731 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -26,6 +26,7 @@ #include "qxl_drv.h" #include "qxl_object.h" +#include #include int qxl_log_level; @@ -307,6 +308,8 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags) goto out; } + drm_kms_helper_poll_init(qdev->ddev); + return 0; out: kfree(qdev); -- cgit v1.2.3