diff options
Diffstat (limited to 'drivers/gpu/drm/qxl')
-rw-r--r-- | drivers/gpu/drm/qxl/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_cmd.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_debugfs.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_dev.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_display.c | 369 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_draw.c | 247 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_drv.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_drv.h | 90 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_dumb.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_fb.c | 300 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_image.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_ioctl.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_kms.c | 91 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_object.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_object.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_prime.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_release.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_ttm.c | 93 |
18 files changed, 389 insertions, 953 deletions
diff --git a/drivers/gpu/drm/qxl/Makefile b/drivers/gpu/drm/qxl/Makefile index 33a7d0c434b7..fc59d42b31af 100644 --- a/drivers/gpu/drm/qxl/Makefile +++ b/drivers/gpu/drm/qxl/Makefile @@ -2,6 +2,6 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_fb.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_release.o qxl_prime.o +qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_release.o qxl_prime.o obj-$(CONFIG_DRM_QXL)+= qxl.o diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 208af9f37914..0a2e51af1230 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -25,6 +25,8 @@ /* QXL cmd/ring handling */ +#include <drm/drm_util.h> + #include "qxl_drv.h" #include "qxl_object.h" @@ -84,6 +86,7 @@ static int qxl_check_header(struct qxl_ring *ring) int ret; struct qxl_ring_header *header = &(ring->ring->header); unsigned long flags; + spin_lock_irqsave(&ring->lock, flags); ret = header->prod - header->cons < header->num_items; if (ret == 0) @@ -97,6 +100,7 @@ int qxl_check_idle(struct qxl_ring *ring) int ret; struct qxl_ring_header *header = &(ring->ring->header); unsigned long flags; + spin_lock_irqsave(&ring->lock, flags); ret = header->prod == header->cons; spin_unlock_irqrestore(&ring->lock, flags); @@ -110,6 +114,7 @@ int qxl_ring_push(struct qxl_ring *ring, uint8_t *elt; int idx, ret; unsigned long flags; + spin_lock_irqsave(&ring->lock, flags); if (header->prod - header->cons == header->num_items) { header->notify_on_cons = header->cons + 1; @@ -156,6 +161,7 @@ static bool qxl_ring_pop(struct qxl_ring *ring, volatile uint8_t *ring_elt; int idx; unsigned long flags; + spin_lock_irqsave(&ring->lock, flags); if (header->cons == header->prod) { header->notify_on_prod = header->cons + 1; @@ -365,29 +371,28 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev) wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC); } - void qxl_io_destroy_primary(struct qxl_device *qdev) { wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); - qdev->primary_created = false; + qdev->primary_bo->is_primary = false; + drm_gem_object_put_unlocked(&qdev->primary_bo->gem_base); + qdev->primary_bo = NULL; } -void qxl_io_create_primary(struct qxl_device *qdev, - unsigned offset, struct qxl_bo *bo) +void qxl_io_create_primary(struct qxl_device *qdev, struct qxl_bo *bo) { struct qxl_surface_create *create; + if (WARN_ON(qdev->primary_bo)) + return; + DRM_DEBUG_DRIVER("qdev %p, ram_header %p\n", qdev, qdev->ram_header); create = &qdev->ram_header->create_surface; create->format = bo->surf.format; create->width = bo->surf.width; create->height = bo->surf.height; create->stride = bo->surf.stride; - if (bo->shadow) { - create->mem = qxl_bo_physical_address(qdev, bo->shadow, offset); - } else { - create->mem = qxl_bo_physical_address(qdev, bo, offset); - } + create->mem = qxl_bo_physical_address(qdev, bo, 0); DRM_DEBUG_DRIVER("mem = %llx, from %p\n", create->mem, bo->kptr); @@ -395,7 +400,9 @@ void qxl_io_create_primary(struct qxl_device *qdev, create->type = QXL_SURF_TYPE_PRIMARY; wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); - qdev->primary_created = true; + qdev->primary_bo = bo; + qdev->primary_bo->is_primary = true; + drm_gem_object_get(&qdev->primary_bo->gem_base); } void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) @@ -455,8 +462,7 @@ void qxl_surface_id_dealloc(struct qxl_device *qdev, } int qxl_hw_surface_alloc(struct qxl_device *qdev, - struct qxl_bo *surf, - struct ttm_mem_reg *new_mem) + struct qxl_bo *surf) { struct qxl_surface_cmd *cmd; struct qxl_release *release; @@ -482,16 +488,7 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev, cmd->u.surface_create.width = surf->surf.width; cmd->u.surface_create.height = surf->surf.height; cmd->u.surface_create.stride = surf->surf.stride; - if (new_mem) { - int slot_id = surf->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot; - struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]); - - /* TODO - need to hold one of the locks to read tbo.offset */ - cmd->u.surface_create.data = slot->high_bits; - - cmd->u.surface_create.data |= (new_mem->start << PAGE_SHIFT) + surf->tbo.bdev->man[new_mem->mem_type].gpu_offset; - } else - cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0); + cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0); cmd->surface_id = surf->surface_id; qxl_release_unmap(qdev, release, &cmd->release_info); diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index 15c84068d3fb..118422549828 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -34,7 +34,6 @@ #include "qxl_drv.h" #include "qxl_object.h" - #if defined(CONFIG_DEBUG_FS) static int qxl_debugfs_irq_received(struct seq_file *m, void *data) @@ -102,9 +101,9 @@ qxl_debugfs_init(struct drm_minor *minor) int qxl_debugfs_add_files(struct qxl_device *qdev, struct drm_info_list *files, - unsigned nfiles) + unsigned int nfiles) { - unsigned i; + unsigned int i; for (i = 0; i < qdev->debugfs_count; i++) { if (qdev->debugfs[i].files == files) { diff --git a/drivers/gpu/drm/qxl/qxl_dev.h b/drivers/gpu/drm/qxl/qxl_dev.h index 94c5aec71920..a0ee41632d7e 100644 --- a/drivers/gpu/drm/qxl/qxl_dev.h +++ b/drivers/gpu/drm/qxl/qxl_dev.h @@ -28,7 +28,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #ifndef H_QXL_DEV #define H_QXL_DEV diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 87d16a0ce01e..08c725544a2f 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -24,11 +24,11 @@ */ #include <linux/crc32.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_probe_helper.h> #include "qxl_drv.h" #include "qxl_object.h" @@ -48,8 +48,8 @@ static int qxl_alloc_client_monitors_config(struct qxl_device *qdev, } if (!qdev->client_monitors_config) { qdev->client_monitors_config = kzalloc( - sizeof(struct qxl_monitors_config) + - sizeof(struct qxl_head) * count, GFP_KERNEL); + struct_size(qdev->client_monitors_config, + heads, count), GFP_KERNEL); if (!qdev->client_monitors_config) return -ENOMEM; } @@ -80,10 +80,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) DRM_DEBUG_KMS("no client monitors configured\n"); return status; } - if (num_monitors > qdev->monitors_config->max_allowed) { + if (num_monitors > qxl_num_crtc) { 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; + qxl_num_crtc, num_monitors); + num_monitors = qxl_num_crtc; } else { num_monitors = qdev->rom->client_monitors_config.count; } @@ -96,8 +96,7 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) return status; } /* we copy max from the client but it isn't used */ - qdev->client_monitors_config->max_allowed = - qdev->monitors_config->max_allowed; + qdev->client_monitors_config->max_allowed = qxl_num_crtc; for (i = 0 ; i < qdev->client_monitors_config->count ; ++i) { struct qxl_urect *c_rect = &qdev->rom->client_monitors_config.heads[i]; @@ -191,20 +190,63 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev) } } -static int qxl_add_monitors_config_modes(struct drm_connector *connector, - unsigned *pwidth, - unsigned *pheight) +static int qxl_check_mode(struct qxl_device *qdev, + unsigned int width, + unsigned int height) +{ + unsigned int stride; + unsigned int size; + + if (check_mul_overflow(width, 4u, &stride)) + return -EINVAL; + if (check_mul_overflow(stride, height, &size)) + return -EINVAL; + if (size > qdev->vram_size) + return -ENOMEM; + return 0; +} + +static int qxl_check_framebuffer(struct qxl_device *qdev, + struct qxl_bo *bo) +{ + return qxl_check_mode(qdev, bo->surf.width, bo->surf.height); +} + +static int qxl_add_mode(struct drm_connector *connector, + unsigned int width, + unsigned int height, + bool preferred) +{ + struct drm_device *dev = connector->dev; + struct qxl_device *qdev = dev->dev_private; + struct drm_display_mode *mode = NULL; + int rc; + + rc = qxl_check_mode(qdev, width, height); + if (rc != 0) + return 0; + + mode = drm_cvt_mode(dev, width, height, 60, false, false, false); + if (preferred) + mode->type |= DRM_MODE_TYPE_PREFERRED; + mode->hdisplay = width; + mode->vdisplay = height; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + return 1; +} + +static int qxl_add_monitors_config_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct qxl_device *qdev = dev->dev_private; struct qxl_output *output = drm_connector_to_qxl_output(connector); int h = output->index; - struct drm_display_mode *mode = NULL; struct qxl_head *head; if (!qdev->monitors_config) return 0; - if (h >= qdev->monitors_config->max_allowed) + if (h >= qxl_num_crtc) return 0; if (!qdev->client_monitors_config) return 0; @@ -214,59 +256,28 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector, head = &qdev->client_monitors_config->heads[h]; DRM_DEBUG_KMS("head %d is %dx%d\n", h, head->width, head->height); - mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false, - false); - mode->type |= DRM_MODE_TYPE_PREFERRED; - mode->hdisplay = head->width; - mode->vdisplay = head->height; - drm_mode_set_name(mode); - *pwidth = head->width; - *pheight = head->height; - drm_mode_probed_add(connector, mode); - /* remember the last custom size for mode validation */ - qdev->monitors_config_width = mode->hdisplay; - qdev->monitors_config_height = mode->vdisplay; - return 1; + return qxl_add_mode(connector, head->width, head->height, true); } static struct mode_size { int w; int h; -} common_modes[] = { - { 640, 480}, +} extra_modes[] = { { 720, 480}, - { 800, 600}, - { 848, 480}, - {1024, 768}, {1152, 768}, - {1280, 720}, - {1280, 800}, {1280, 854}, - {1280, 960}, - {1280, 1024}, - {1440, 900}, - {1400, 1050}, - {1680, 1050}, - {1600, 1200}, - {1920, 1080}, - {1920, 1200} }; -static int qxl_add_common_modes(struct drm_connector *connector, - unsigned pwidth, - unsigned pheight) +static int qxl_add_extra_modes(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode = NULL; - int i; - for (i = 0; i < ARRAY_SIZE(common_modes); i++) { - mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, - 60, false, false, false); - if (common_modes[i].w == pwidth && common_modes[i].h == pheight) - mode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - } - return i - 1; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(extra_modes); i++) + ret += qxl_add_mode(connector, + extra_modes[i].w, + extra_modes[i].h, + false); + return ret; } static void qxl_send_monitors_config(struct qxl_device *qdev) @@ -301,13 +312,12 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, struct qxl_head head; int oldcount, i = qcrtc->index; - if (!qdev->primary_created) { + if (!qdev->primary_bo) { DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason); return; } - if (!qdev->monitors_config || - qdev->monitors_config->max_allowed <= i) + if (!qdev->monitors_config || qxl_num_crtc <= i) return; head.id = i; @@ -315,12 +325,15 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, oldcount = qdev->monitors_config->count; if (crtc->state->active) { struct drm_display_mode *mode = &crtc->mode; + head.width = mode->hdisplay; head.height = mode->vdisplay; head.x = crtc->x; head.y = crtc->y; if (qdev->monitors_config->count < i + 1) qdev->monitors_config->count = i + 1; + if (qdev->primary_bo == qdev->dumb_shadow_bo) + head.x += qdev->dumb_heads[i].x; } else if (i > 0) { head.width = 0; head.height = 0; @@ -346,9 +359,10 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, if (oldcount != qdev->monitors_config->count) DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n", oldcount, qdev->monitors_config->count, - qdev->monitors_config->max_allowed); + qxl_num_crtc); qdev->monitors_config->heads[i] = head; + qdev->monitors_config->max_allowed = qxl_num_crtc; qxl_send_monitors_config(qdev); } @@ -391,21 +405,23 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = { static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, - unsigned flags, unsigned color, + unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned num_clips) + unsigned int num_clips) { /* TODO: vmwgfx where this was cribbed from had locking. Why? */ struct qxl_device *qdev = fb->dev->dev_private; struct drm_clip_rect norect; struct qxl_bo *qobj; + bool is_primary; int inc = 1; drm_modeset_lock_all(fb->dev); qobj = gem_to_qxl_bo(fb->obj[0]); /* if we aren't primary surface ignore this */ - if (!qobj->is_primary) { + is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary; + if (!is_primary) { drm_modeset_unlock_all(fb->dev); return 0; } @@ -422,7 +438,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, } qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, - clips, num_clips, inc); + clips, num_clips, inc, 0); drm_modeset_unlock_all(fb->dev); @@ -464,12 +480,7 @@ static int qxl_primary_atomic_check(struct drm_plane *plane, bo = gem_to_qxl_bo(state->fb->obj[0]); - if (bo->surf.stride * bo->surf.height > qdev->vram_size) { - DRM_ERROR("Mode doesn't fit in vram size (vgamem)"); - return -EINVAL; - } - - return 0; + return qxl_check_framebuffer(qdev, bo); } static int qxl_primary_apply_cursor(struct drm_plane *plane) @@ -524,15 +535,14 @@ static void qxl_primary_atomic_update(struct drm_plane *plane, { struct qxl_device *qdev = plane->dev->dev_private; struct qxl_bo *bo = gem_to_qxl_bo(plane->state->fb->obj[0]); - struct qxl_bo *bo_old; + struct qxl_bo *bo_old, *primary; struct drm_clip_rect norect = { .x1 = 0, .y1 = 0, .x2 = plane->state->fb->width, .y2 = plane->state->fb->height }; - int ret; - bool same_shadow = false; + uint32_t dumb_shadow_offset = 0; if (old_state->fb) { bo_old = gem_to_qxl_bo(old_state->fb->obj[0]); @@ -540,32 +550,21 @@ static void qxl_primary_atomic_update(struct drm_plane *plane, bo_old = NULL; } - if (bo == bo_old) - return; - - if (bo_old && bo_old->shadow && bo->shadow && - bo_old->shadow == bo->shadow) { - same_shadow = true; - } + primary = bo->shadow ? bo->shadow : bo; - if (bo_old && bo_old->is_primary) { - if (!same_shadow) + if (!primary->is_primary) { + if (qdev->primary_bo) qxl_io_destroy_primary(qdev); - bo_old->is_primary = false; - - ret = qxl_primary_apply_cursor(plane); - if (ret) - DRM_ERROR( - "could not set cursor after creating primary"); + qxl_io_create_primary(qdev, primary); + qxl_primary_apply_cursor(plane); } - if (!bo->is_primary) { - if (!same_shadow) - qxl_io_create_primary(qdev, 0, bo); - bo->is_primary = true; - } + if (bo->is_dumb) + dumb_shadow_offset = + qdev->dumb_heads[plane->state->crtc->index].x; - qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1); + qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1, + dumb_shadow_offset); } static void qxl_primary_atomic_disable(struct drm_plane *plane, @@ -620,10 +619,14 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane, if (ret) goto out_kunmap; - ret = qxl_release_reserve_list(release, true); + ret = qxl_bo_pin(cursor_bo); if (ret) goto out_free_bo; + ret = qxl_release_reserve_list(release, true); + if (ret) + goto out_unpin; + ret = qxl_bo_kmap(cursor_bo, (void **)&cursor); if (ret) goto out_backoff; @@ -668,15 +671,17 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane, qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); qxl_release_fence_buffer_objects(release); - if (old_cursor_bo) - qxl_bo_unref(&old_cursor_bo); - + if (old_cursor_bo != NULL) + qxl_bo_unpin(old_cursor_bo); + qxl_bo_unref(&old_cursor_bo); qxl_bo_unref(&cursor_bo); return; out_backoff: qxl_release_backoff_reserve_list(release); +out_unpin: + qxl_bo_unpin(cursor_bo); out_free_bo: qxl_bo_unref(&cursor_bo); out_kunmap: @@ -715,12 +720,68 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane, qxl_release_fence_buffer_objects(release); } +static void qxl_update_dumb_head(struct qxl_device *qdev, + int index, struct qxl_bo *bo) +{ + uint32_t width, height; + + if (index >= qdev->monitors_config->max_allowed) + return; + + if (bo && bo->is_dumb) { + width = bo->surf.width; + height = bo->surf.height; + } else { + width = 0; + height = 0; + } + + if (qdev->dumb_heads[index].width == width && + qdev->dumb_heads[index].height == height) + return; + + DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index, + qdev->dumb_heads[index].width, + qdev->dumb_heads[index].height, + width, height); + qdev->dumb_heads[index].width = width; + qdev->dumb_heads[index].height = height; +} + +static void qxl_calc_dumb_shadow(struct qxl_device *qdev, + struct qxl_surface *surf) +{ + struct qxl_head *head; + int i; + + memset(surf, 0, sizeof(*surf)); + for (i = 0; i < qdev->monitors_config->max_allowed; i++) { + head = qdev->dumb_heads + i; + head->x = surf->width; + surf->width += head->width; + if (surf->height < head->height) + surf->height = head->height; + } + if (surf->width < 64) + surf->width = 64; + if (surf->height < 64) + surf->height = 64; + surf->format = SPICE_SURFACE_FMT_32_xRGB; + surf->stride = surf->width * 4; + + if (!qdev->dumb_shadow_bo || + qdev->dumb_shadow_bo->surf.width != surf->width || + qdev->dumb_shadow_bo->surf.height != surf->height) + DRM_DEBUG("%dx%d\n", surf->width, surf->height); +} + static int qxl_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { struct qxl_device *qdev = plane->dev->dev_private; struct drm_gem_object *obj; - struct qxl_bo *user_bo, *old_bo = NULL; + struct qxl_bo *user_bo; + struct qxl_surface surf; int ret; if (!new_state->fb) @@ -730,32 +791,34 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane, user_bo = gem_to_qxl_bo(obj); if (plane->type == DRM_PLANE_TYPE_PRIMARY && - user_bo->is_dumb && !user_bo->shadow) { - if (plane->state->fb) { - obj = plane->state->fb->obj[0]; - old_bo = gem_to_qxl_bo(obj); + user_bo->is_dumb) { + qxl_update_dumb_head(qdev, new_state->crtc->index, + user_bo); + qxl_calc_dumb_shadow(qdev, &surf); + if (!qdev->dumb_shadow_bo || + qdev->dumb_shadow_bo->surf.width != surf.width || + qdev->dumb_shadow_bo->surf.height != surf.height) { + if (qdev->dumb_shadow_bo) { + drm_gem_object_put_unlocked + (&qdev->dumb_shadow_bo->gem_base); + qdev->dumb_shadow_bo = NULL; + } + qxl_bo_create(qdev, surf.height * surf.stride, + true, true, QXL_GEM_DOMAIN_SURFACE, &surf, + &qdev->dumb_shadow_bo); } - if (old_bo && old_bo->shadow && - user_bo->gem_base.size == old_bo->gem_base.size && - plane->state->crtc == new_state->crtc && - plane->state->crtc_w == new_state->crtc_w && - plane->state->crtc_h == new_state->crtc_h && - plane->state->src_x == new_state->src_x && - plane->state->src_y == new_state->src_y && - plane->state->src_w == new_state->src_w && - plane->state->src_h == new_state->src_h && - plane->state->rotation == new_state->rotation && - plane->state->zpos == new_state->zpos) { - drm_gem_object_get(&old_bo->shadow->gem_base); - user_bo->shadow = old_bo->shadow; - } else { - qxl_bo_create(qdev, user_bo->gem_base.size, - true, true, QXL_GEM_DOMAIN_VRAM, NULL, - &user_bo->shadow); + if (user_bo->shadow != qdev->dumb_shadow_bo) { + if (user_bo->shadow) { + drm_gem_object_put_unlocked + (&user_bo->shadow->gem_base); + user_bo->shadow = NULL; + } + drm_gem_object_get(&qdev->dumb_shadow_bo->gem_base); + user_bo->shadow = qdev->dumb_shadow_bo; } } - ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL); + ret = qxl_bo_pin(user_bo); if (ret) return ret; @@ -780,7 +843,7 @@ static void qxl_plane_cleanup_fb(struct drm_plane *plane, user_bo = gem_to_qxl_bo(obj); qxl_bo_unpin(user_bo); - if (user_bo->shadow && !user_bo->is_primary) { + if (old_state->fb != plane->state->fb && user_bo->shadow) { drm_gem_object_put_unlocked(&user_bo->shadow->gem_base); user_bo->shadow = NULL; } @@ -917,14 +980,26 @@ free_mem: static int qxl_conn_get_modes(struct drm_connector *connector) { - unsigned pwidth = 1024; - unsigned pheight = 768; + struct drm_device *dev = connector->dev; + struct qxl_device *qdev = dev->dev_private; + struct qxl_output *output = drm_connector_to_qxl_output(connector); + unsigned int pwidth = 1024; + unsigned int pheight = 768; int ret = 0; - ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight); - if (ret < 0) - return ret; - ret += qxl_add_common_modes(connector, pwidth, pheight); + if (qdev->client_monitors_config) { + struct qxl_head *head; + head = &qdev->client_monitors_config->heads[output->index]; + if (head->width) + pwidth = head->width; + if (head->height) + pheight = head->height; + } + + ret += drm_add_modes_noedid(connector, 8192, 8192); + ret += qxl_add_extra_modes(connector); + ret += qxl_add_monitors_config_modes(connector); + drm_set_preferred_mode(connector, pwidth, pheight); return ret; } @@ -933,20 +1008,11 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector, { struct drm_device *ddev = connector->dev; struct qxl_device *qdev = ddev->dev_private; - int i; - - /* TODO: is this called for user defined modes? (xrandr --add-mode) - * TODO: check that the mode fits in the framebuffer */ - if(qdev->monitors_config_width == mode->hdisplay && - qdev->monitors_config_height == mode->vdisplay) - return MODE_OK; + if (qxl_check_mode(qdev, mode->hdisplay, mode->vdisplay) != 0) + return MODE_BAD; - for (i = 0; i < ARRAY_SIZE(common_modes); i++) { - if (common_modes[i].w == mode->hdisplay && common_modes[i].h == mode->vdisplay) - return MODE_OK; - } - return MODE_BAD; + return MODE_OK; } static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) @@ -958,7 +1024,6 @@ static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) return &qxl_output->enc; } - static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = { }; @@ -1003,7 +1068,6 @@ static void qxl_conn_destroy(struct drm_connector *connector) } static const struct drm_connector_funcs qxl_connector_funcs = { - .dpms = drm_helper_connector_dpms, .detect = qxl_conn_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = qxl_conn_destroy, @@ -1090,9 +1154,8 @@ int qxl_create_monitors_object(struct qxl_device *qdev) { 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); + qxl_num_crtc * sizeof(struct qxl_head); ret = qxl_gem_object_create(qdev, monitors_config_size, 0, QXL_GEM_DOMAIN_VRAM, @@ -1103,7 +1166,7 @@ int qxl_create_monitors_object(struct qxl_device *qdev) } qdev->monitors_config_bo = gem_to_qxl_bo(gobj); - ret = qxl_bo_pin(qdev->monitors_config_bo, QXL_GEM_DOMAIN_VRAM, NULL); + ret = qxl_bo_pin(qdev->monitors_config_bo); if (ret) return ret; @@ -1114,7 +1177,12 @@ int qxl_create_monitors_object(struct qxl_device *qdev) 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; + qdev->dumb_heads = kcalloc(qxl_num_crtc, sizeof(qdev->dumb_heads[0]), + GFP_KERNEL); + if (!qdev->dumb_heads) { + qxl_destroy_monitors_object(qdev); + return -ENOMEM; + } return 0; } @@ -1166,18 +1234,11 @@ int qxl_modeset_init(struct qxl_device *qdev) qxl_display_read_client_monitors_config(qdev); drm_mode_config_reset(&qdev->ddev); - - /* primary surface must be created by this point, to allow - * issuing command queue commands and having them read by - * spice server. */ - qxl_fbdev_init(qdev); return 0; } void qxl_modeset_fini(struct qxl_device *qdev) { - qxl_fbdev_fini(qdev); - qxl_destroy_monitors_object(qdev); drm_mode_config_cleanup(&qdev->ddev); } diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index cc5b32e749ce..97c3f1a95a32 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -25,7 +25,7 @@ static int alloc_clips(struct qxl_device *qdev, struct qxl_release *release, - unsigned num_clips, + unsigned int num_clips, struct qxl_bo **clips_bo) { int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips; @@ -37,7 +37,7 @@ static int alloc_clips(struct qxl_device *qdev, * the qxl_clip_rects. This is *not* the same as the memory allocated * on the device, it is offset to qxl_clip_rects.chunk.data */ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, - unsigned num_clips, + unsigned int num_clips, struct qxl_bo *clips_bo) { struct qxl_clip_rects *dev_clips; @@ -109,151 +109,6 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type, return 0; } -static int alloc_palette_object(struct qxl_device *qdev, - struct qxl_release *release, - struct qxl_bo **palette_bo) -{ - return qxl_alloc_bo_reserved(qdev, release, - sizeof(struct qxl_palette) + sizeof(uint32_t) * 2, - palette_bo); -} - -static int qxl_palette_create_1bit(struct qxl_bo *palette_bo, - struct qxl_release *release, - const struct qxl_fb_image *qxl_fb_image) -{ - const struct fb_image *fb_image = &qxl_fb_image->fb_image; - uint32_t visual = qxl_fb_image->visual; - const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette; - struct qxl_palette *pal; - int ret; - uint32_t fgcolor, bgcolor; - static uint64_t unique; /* we make no attempt to actually set this - * correctly globaly, since that would require - * tracking all of our palettes. */ - ret = qxl_bo_kmap(palette_bo, (void **)&pal); - if (ret) - return ret; - pal->num_ents = 2; - pal->unique = unique++; - if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) { - /* NB: this is the only used branch currently. */ - fgcolor = pseudo_palette[fb_image->fg_color]; - bgcolor = pseudo_palette[fb_image->bg_color]; - } else { - fgcolor = fb_image->fg_color; - bgcolor = fb_image->bg_color; - } - pal->ents[0] = bgcolor; - pal->ents[1] = fgcolor; - qxl_bo_kunmap(palette_bo); - return 0; -} - -void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, - int stride /* filled in if 0 */) -{ - struct qxl_device *qdev = qxl_fb_image->qdev; - struct qxl_drawable *drawable; - struct qxl_rect rect; - const struct fb_image *fb_image = &qxl_fb_image->fb_image; - int x = fb_image->dx; - int y = fb_image->dy; - int width = fb_image->width; - int height = fb_image->height; - const char *src = fb_image->data; - int depth = fb_image->depth; - struct qxl_release *release; - struct qxl_image *image; - int ret; - struct qxl_drm_image *dimage; - struct qxl_bo *palette_bo = NULL; - if (stride == 0) - stride = depth * width / 8; - - ret = alloc_drawable(qdev, &release); - if (ret) - return; - - ret = qxl_image_alloc_objects(qdev, release, - &dimage, - height, stride); - if (ret) - goto out_free_drawable; - - if (depth == 1) { - ret = alloc_palette_object(qdev, release, &palette_bo); - if (ret) - goto out_free_image; - } - - /* do a reservation run over all the objects we just allocated */ - ret = qxl_release_reserve_list(release, true); - if (ret) - goto out_free_palette; - - rect.left = x; - rect.right = x + width; - rect.top = y; - rect.bottom = y + height; - - ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release); - if (ret) { - qxl_release_backoff_reserve_list(release); - goto out_free_palette; - } - - ret = qxl_image_init(qdev, release, dimage, - (const uint8_t *)src, 0, 0, - width, height, depth, stride); - if (ret) { - qxl_release_backoff_reserve_list(release); - qxl_release_free(qdev, release); - return; - } - - if (depth == 1) { - void *ptr; - ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image); - - ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0); - image = ptr; - image->u.bitmap.palette = - qxl_bo_physical_address(qdev, palette_bo, 0); - qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr); - } - - drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); - - drawable->u.copy.src_area.top = 0; - drawable->u.copy.src_area.bottom = height; - drawable->u.copy.src_area.left = 0; - drawable->u.copy.src_area.right = width; - - drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; - drawable->u.copy.scale_mode = 0; - drawable->u.copy.mask.flags = 0; - drawable->u.copy.mask.pos.x = 0; - drawable->u.copy.mask.pos.y = 0; - drawable->u.copy.mask.bitmap = 0; - - drawable->u.copy.src_bitmap = - qxl_bo_physical_address(qdev, dimage->bo, 0); - qxl_release_unmap(qdev, release, &drawable->release_info); - - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); - qxl_release_fence_buffer_objects(release); - -out_free_palette: - if (palette_bo) - qxl_bo_unref(&palette_bo); -out_free_image: - qxl_image_free_objects(qdev, dimage); -out_free_drawable: - if (ret) - free_drawable(qdev, release); -} - /* push a draw command using the given clipping rectangles as * the sources from the shadow framebuffer. * @@ -264,9 +119,10 @@ out_free_drawable: void qxl_draw_dirty_fb(struct qxl_device *qdev, struct drm_framebuffer *fb, struct qxl_bo *bo, - unsigned flags, unsigned color, + unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned num_clips, int inc) + unsigned int num_clips, int inc, + uint32_t dumb_shadow_offset) { /* * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should @@ -294,6 +150,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, if (ret) return; + clips->x1 += dumb_shadow_offset; + clips->x2 += dumb_shadow_offset; + left = clips->x1; right = clips->x2; top = clips->y1; @@ -340,9 +199,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, if (ret) goto out_release_backoff; - ret = qxl_image_init(qdev, release, dimage, surface_base, - left, top, width, height, depth, stride); + left - dumb_shadow_offset, + top, width, height, depth, stride); qxl_bo_kunmap(bo); if (ret) goto out_release_backoff; @@ -397,89 +256,3 @@ out_free_drawable: free_drawable(qdev, release); } - -void qxl_draw_copyarea(struct qxl_device *qdev, - u32 width, u32 height, - u32 sx, u32 sy, - u32 dx, u32 dy) -{ - struct qxl_drawable *drawable; - struct qxl_rect rect; - struct qxl_release *release; - int ret; - - ret = alloc_drawable(qdev, &release); - if (ret) - return; - - /* do a reservation run over all the objects we just allocated */ - ret = qxl_release_reserve_list(release, true); - if (ret) - goto out_free_release; - - rect.left = dx; - rect.top = dy; - rect.right = dx + width; - rect.bottom = dy + height; - ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release); - if (ret) { - qxl_release_backoff_reserve_list(release); - goto out_free_release; - } - - drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); - drawable->u.copy_bits.src_pos.x = sx; - drawable->u.copy_bits.src_pos.y = sy; - qxl_release_unmap(qdev, release, &drawable->release_info); - - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); - qxl_release_fence_buffer_objects(release); - -out_free_release: - if (ret) - free_drawable(qdev, release); -} - -void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec) -{ - struct qxl_device *qdev = qxl_draw_fill_rec->qdev; - struct qxl_rect rect = qxl_draw_fill_rec->rect; - uint32_t color = qxl_draw_fill_rec->color; - uint16_t rop = qxl_draw_fill_rec->rop; - struct qxl_drawable *drawable; - struct qxl_release *release; - int ret; - - ret = alloc_drawable(qdev, &release); - if (ret) - return; - - /* do a reservation run over all the objects we just allocated */ - ret = qxl_release_reserve_list(release, true); - if (ret) - goto out_free_release; - - ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release); - if (ret) { - qxl_release_backoff_reserve_list(release); - goto out_free_release; - } - - drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); - drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID; - drawable->u.fill.brush.u.color = color; - drawable->u.fill.rop_descriptor = rop; - drawable->u.fill.mask.flags = 0; - drawable->u.fill.mask.pos.x = 0; - drawable->u.fill.mask.pos.y = 0; - drawable->u.fill.mask.bitmap = 0; - - qxl_release_unmap(qdev, release, &drawable->release_info); - - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); - qxl_release_fence_buffer_objects(release); - -out_free_release: - if (ret) - free_drawable(qdev, release); -} diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 13c8a662f9b4..f33e349c4ec5 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -33,7 +33,8 @@ #include <drm/drmP.h> #include <drm/drm.h> -#include <drm/drm_crtc_helper.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_probe_helper.h> #include "qxl_drv.h" #include "qxl_object.h" @@ -78,6 +79,10 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto free_dev; + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "qxl"); + if (ret) + goto disable_pci; + ret = qxl_device_init(qdev, &qxl_driver, pdev); if (ret) goto disable_pci; @@ -93,6 +98,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto modeset_cleanup; + drm_fbdev_generic_setup(&qdev->ddev, 32); return 0; modeset_cleanup: @@ -242,7 +248,6 @@ static struct pci_driver qxl_pci_driver = { static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_ATOMIC, .dumb_create = qxl_mode_dumb_create, diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 8ff70a7281a7..4a0331b3ff7d 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -23,7 +23,6 @@ * Alon Levy */ - #ifndef QXL_DRV_H #define QXL_DRV_H @@ -83,16 +82,17 @@ struct qxl_bo { struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; - unsigned pin_count; + unsigned int pin_count; void *kptr; + unsigned int map_count; int type; /* Constant after initialization */ struct drm_gem_object gem_base; - bool is_primary; /* is this now a primary surface */ - bool is_dumb; + unsigned int is_primary:1; /* is this now a primary surface */ + unsigned int is_dumb:1; struct qxl_bo *shadow; - bool hw_surf_alloc; + unsigned int hw_surf_alloc:1; struct qxl_surface surf; uint32_t surface_id; struct qxl_release *surf_create; @@ -127,18 +127,17 @@ struct qxl_output { #define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc) struct qxl_mman { - struct ttm_bo_global_ref bo_global_ref; - struct drm_global_reference mem_global_ref; - bool mem_global_referenced; struct ttm_bo_device bdev; }; - struct qxl_memslot { + int index; + const char *name; uint8_t generation; uint64_t start_phys_addr; - uint64_t end_phys_addr; + uint64_t size; uint64_t high_bits; + uint64_t gpu_offset; }; enum { @@ -191,12 +190,12 @@ struct qxl_draw_fill { */ struct qxl_debugfs { struct drm_info_list *files; - unsigned num_files; + unsigned int num_files; }; int qxl_debugfs_add_files(struct qxl_device *rdev, struct drm_info_list *files, - unsigned nfiles); + unsigned int nfiles); int qxl_debugfs_fence_init(struct qxl_device *rdev); struct qxl_device; @@ -221,8 +220,6 @@ struct qxl_device { struct qxl_mman mman; struct qxl_gem gem; - struct drm_fb_helper fb_helper; - void *ram_physical; struct qxl_ring *release_ring; @@ -231,16 +228,12 @@ struct qxl_device { struct qxl_ram_header *ram_header; - bool primary_created; - - struct qxl_memslot *mem_slots; - uint8_t n_mem_slots; + struct qxl_bo *primary_bo; + struct qxl_bo *dumb_shadow_bo; + struct qxl_head *dumb_heads; - uint8_t main_mem_slot; - uint8_t surfaces_mem_slot; - uint8_t slot_id_bits; - uint8_t slot_gen_bits; - uint64_t va_slot_mask; + struct qxl_memslot main_slot; + struct qxl_memslot surfaces_slot; spinlock_t release_lock; struct idr release_idr; @@ -254,7 +247,7 @@ struct qxl_device { atomic_t irq_received_display; atomic_t irq_received_cursor; atomic_t irq_received_io_cmd; - unsigned irq_received_error; + unsigned int irq_received_error; wait_queue_head_t display_event; wait_queue_head_t cursor_event; wait_queue_head_t io_cmd_event; @@ -262,7 +255,7 @@ struct qxl_device { /* debugfs */ struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS]; - unsigned debugfs_count; + unsigned int debugfs_count; struct mutex update_area_mutex; @@ -313,30 +306,20 @@ 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) -{ - DRM_DEBUG_DRIVER("not implemented (%lu)\n", physical); - return 0; -} - static inline uint64_t qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo, unsigned long offset) { - int slot_id = bo->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot; - struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]); + struct qxl_memslot *slot = + (bo->tbo.mem.mem_type == TTM_PL_VRAM) + ? &qdev->main_slot : &qdev->surfaces_slot; + + WARN_ON_ONCE((bo->tbo.offset & slot->gpu_offset) != slot->gpu_offset); /* TODO - need to hold one of the locks to read tbo.offset */ - return slot->high_bits | (bo->tbo.offset + offset); + return slot->high_bits | (bo->tbo.offset - slot->gpu_offset + offset); } -/* qxl_fb.c */ -#define QXLFB_CONN_LIMIT 1 - -int qxl_fbdev_init(struct qxl_device *qdev); -void qxl_fbdev_fini(struct qxl_device *qdev); - /* qxl_display.c */ void qxl_display_read_client_monitors_config(struct qxl_device *qdev); int qxl_create_monitors_object(struct qxl_device *qdev); @@ -372,7 +355,6 @@ int qxl_mode_dumb_mmap(struct drm_file *filp, struct drm_device *dev, uint32_t handle, uint64_t *offset_p); - /* qxl ttm */ int qxl_ttm_init(struct qxl_device *qdev); void qxl_ttm_fini(struct qxl_device *qdev); @@ -398,7 +380,6 @@ void qxl_update_screen(struct qxl_device *qxl); /* qxl io operations (qxl_cmd.c) */ void qxl_io_create_primary(struct qxl_device *qdev, - 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); @@ -443,22 +424,13 @@ int qxl_alloc_bo_reserved(struct qxl_device *qdev, struct qxl_bo **_bo); /* qxl drawing commands */ -void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, - int stride /* filled in if 0 */); - void qxl_draw_dirty_fb(struct qxl_device *qdev, struct drm_framebuffer *fb, struct qxl_bo *bo, - unsigned flags, unsigned color, + unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned num_clips, int inc); - -void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec); - -void qxl_draw_copyarea(struct qxl_device *qdev, - u32 width, u32 height, - u32 sx, u32 sy, - u32 dx, u32 dy); + unsigned int num_clips, int inc, + uint32_t dumb_shadow_offset); void qxl_release_free(struct qxl_device *qdev, struct qxl_release *release); @@ -491,20 +463,16 @@ int qxl_gem_prime_mmap(struct drm_gem_object *obj, int qxl_irq_init(struct qxl_device *qdev); irqreturn_t qxl_irq_handler(int irq, void *arg); -/* qxl_fb.c */ -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, - unsigned nfiles); + unsigned int nfiles); int qxl_surface_id_alloc(struct qxl_device *qdev, struct qxl_bo *surf); void qxl_surface_id_dealloc(struct qxl_device *qdev, uint32_t surface_id); int qxl_hw_surface_alloc(struct qxl_device *qdev, - struct qxl_bo *surf, - struct ttm_mem_reg *mem); + struct qxl_bo *surf); int qxl_hw_surface_dealloc(struct qxl_device *qdev, struct qxl_bo *surf); diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c index c666b89eed5d..272d19b677d8 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c @@ -38,6 +38,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv, int r; struct qxl_surface surf; uint32_t pitch, format; + pitch = args->width * ((args->bpp + 1) / 8); args->size = pitch * args->height; args->size = ALIGN(args->size, PAGE_SIZE); @@ -52,13 +53,13 @@ int qxl_mode_dumb_create(struct drm_file *file_priv, default: return -EINVAL; } - + surf.width = args->width; surf.height = args->height; surf.stride = pitch; surf.format = format; r = qxl_gem_object_create_with_handle(qdev, file_priv, - QXL_GEM_DOMAIN_VRAM, + QXL_GEM_DOMAIN_SURFACE, args->size, &surf, &qobj, &handle); if (r) diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c deleted file mode 100644 index 2294b7f14fdf..000000000000 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright © 2013 Red Hat - * - * 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: - * David Airlie - */ -#include <linux/module.h> - -#include <drm/drmP.h> -#include <drm/drm.h> -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> - -#include "qxl_drv.h" - -#include "qxl_object.h" - -static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image, - struct qxl_device *qdev, struct fb_info *info, - const struct fb_image *image) -{ - qxl_fb_image->qdev = qdev; - if (info) { - qxl_fb_image->visual = info->fix.visual; - if (qxl_fb_image->visual == FB_VISUAL_TRUECOLOR || - qxl_fb_image->visual == FB_VISUAL_DIRECTCOLOR) - memcpy(&qxl_fb_image->pseudo_palette, - info->pseudo_palette, - sizeof(qxl_fb_image->pseudo_palette)); - } else { - /* fallback */ - if (image->depth == 1) - qxl_fb_image->visual = FB_VISUAL_MONO10; - else - qxl_fb_image->visual = FB_VISUAL_DIRECTCOLOR; - } - if (image) { - memcpy(&qxl_fb_image->fb_image, image, - sizeof(qxl_fb_image->fb_image)); - } -} - -static struct fb_ops qxlfb_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, -}; - -static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj) -{ - struct qxl_bo *qbo = gem_to_qxl_bo(gobj); - - qxl_bo_kunmap(qbo); - qxl_bo_unpin(qbo); - - drm_gem_object_put_unlocked(gobj); -} - -static int qxlfb_create_pinned_object(struct qxl_device *qdev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_gem_object *gobj = NULL; - struct qxl_bo *qbo = NULL; - int ret; - int aligned_size, size; - int height = mode_cmd->height; - - size = mode_cmd->pitches[0] * height; - aligned_size = ALIGN(size, PAGE_SIZE); - /* TODO: unallocate and reallocate surface0 for real. Hack to just - * have a large enough surface0 for 1024x768 Xorg 32bpp mode */ - ret = qxl_gem_object_create(qdev, aligned_size, 0, - QXL_GEM_DOMAIN_SURFACE, - false, /* is discardable */ - false, /* is kernel (false means device) */ - NULL, - &gobj); - if (ret) { - pr_err("failed to allocate framebuffer (%d)\n", - aligned_size); - return -ENOMEM; - } - qbo = gem_to_qxl_bo(gobj); - - qbo->surf.width = mode_cmd->width; - qbo->surf.height = mode_cmd->height; - qbo->surf.stride = mode_cmd->pitches[0]; - qbo->surf.format = SPICE_SURFACE_FMT_32_xRGB; - - ret = qxl_bo_pin(qbo, QXL_GEM_DOMAIN_SURFACE, NULL); - if (ret) { - goto out_unref; - } - ret = qxl_bo_kmap(qbo, NULL); - - if (ret) - goto out_unref; - - *gobj_p = gobj; - return 0; -out_unref: - qxlfb_destroy_pinned_object(gobj); - *gobj_p = NULL; - return ret; -} - -/* - * FIXME - * It should not be necessary to have a special dirty() callback for fbdev. - */ -static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips) -{ - struct qxl_device *qdev = fb->dev->dev_private; - struct fb_info *info = qdev->fb_helper.fbdev; - struct qxl_fb_image qxl_fb_image; - struct fb_image *image = &qxl_fb_image.fb_image; - - /* TODO: hard coding 32 bpp */ - int stride = fb->pitches[0]; - - /* - * we are using a shadow draw buffer, at qdev->surface0_shadow - */ - image->dx = clips->x1; - image->dy = clips->y1; - image->width = clips->x2 - clips->x1; - image->height = clips->y2 - clips->y1; - image->fg_color = 0xffffffff; /* unused, just to avoid uninitialized - warnings */ - image->bg_color = 0; - image->depth = 32; /* TODO: take from somewhere? */ - image->cmap.start = 0; - image->cmap.len = 0; - image->cmap.red = NULL; - image->cmap.green = NULL; - image->cmap.blue = NULL; - image->cmap.transp = NULL; - image->data = info->screen_base + (clips->x1 * 4) + (stride * clips->y1); - - qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL); - qxl_draw_opaque_fb(&qxl_fb_image, stride); - - return 0; -} - -static const struct drm_framebuffer_funcs qxlfb_fb_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, - .dirty = qxlfb_framebuffer_dirty, -}; - -static int qxlfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct qxl_device *qdev = - container_of(helper, struct qxl_device, fb_helper); - struct fb_info *info; - struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_gem_object *gobj = NULL; - struct qxl_bo *qbo = NULL; - int ret; - int bpp = sizes->surface_bpp; - int depth = sizes->surface_depth; - void *shadow; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); - - ret = qxlfb_create_pinned_object(qdev, &mode_cmd, &gobj); - if (ret < 0) - return ret; - - qbo = gem_to_qxl_bo(gobj); - DRM_DEBUG_DRIVER("%dx%d %d\n", mode_cmd.width, - mode_cmd.height, mode_cmd.pitches[0]); - - shadow = vmalloc(array_size(mode_cmd.pitches[0], mode_cmd.height)); - /* TODO: what's the usual response to memory allocation errors? */ - BUG_ON(!shadow); - DRM_DEBUG_DRIVER("surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n", - qxl_bo_gpu_offset(qbo), qxl_bo_mmap_offset(qbo), - qbo->kptr, shadow); - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out_unref; - } - - info->par = helper; - - fb = drm_gem_fbdev_fb_create(&qdev->ddev, sizes, 64, gobj, - &qxlfb_fb_funcs); - if (IS_ERR(fb)) { - DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb)); - ret = PTR_ERR(fb); - goto out_unref; - } - - /* setup helper with fb data */ - qdev->fb_helper.fb = fb; - - strcpy(info->fix.id, "qxldrmfb"); - - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); - - info->fbops = &qxlfb_ops; - - /* - * TODO: using gobj->size in various places in this function. Not sure - * what the difference between the different sizes is. - */ - info->fix.smem_start = qdev->vram_base; /* TODO - correct? */ - info->fix.smem_len = gobj->size; - info->screen_base = shadow; - info->screen_size = gobj->size; - - drm_fb_helper_fill_var(info, &qdev->fb_helper, sizes->fb_width, - sizes->fb_height); - - /* setup aperture base/size for vesafb takeover */ - info->apertures->ranges[0].base = qdev->ddev.mode_config.fb_base; - info->apertures->ranges[0].size = qdev->vram_size; - - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - - if (info->screen_base == NULL) { - ret = -ENOSPC; - goto out_unref; - } - - /* XXX error handling. */ - drm_fb_helper_defio_init(helper); - - DRM_INFO("fb mappable at 0x%lX, size %lu\n", info->fix.smem_start, (unsigned long)info->screen_size); - DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", - fb->format->depth, fb->pitches[0], fb->width, fb->height); - return 0; - -out_unref: - if (qbo) { - qxl_bo_kunmap(qbo); - qxl_bo_unpin(qbo); - } - drm_gem_object_put_unlocked(gobj); - return ret; -} - -static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = { - .fb_probe = qxlfb_create, -}; - -int qxl_fbdev_init(struct qxl_device *qdev) -{ - return drm_fb_helper_fbdev_setup(&qdev->ddev, &qdev->fb_helper, - &qxl_fb_helper_funcs, 32, - QXLFB_CONN_LIMIT); -} - -void qxl_fbdev_fini(struct qxl_device *qdev) -{ - struct fb_info *fbi = qdev->fb_helper.fbdev; - void *shadow = fbi ? fbi->screen_buffer : NULL; - - drm_fb_helper_fbdev_teardown(&qdev->ddev); - vfree(shadow); -} diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c index 7fbcc35e8ad3..43688ecdd8a0 100644 --- a/drivers/gpu/drm/qxl/qxl_image.c +++ b/drivers/gpu/drm/qxl/qxl_image.c @@ -136,6 +136,7 @@ qxl_image_init_helper(struct qxl_device *qdev, int remain; int page; int size; + if (stride == linesize && chunk_stride == stride) { remain = linesize * height; page = 0; @@ -162,7 +163,8 @@ qxl_image_init_helper(struct qxl_device *qdev, page++; } } else { - unsigned page_base, page_offset, out_offset; + unsigned int page_base, page_offset, out_offset; + for (i = 0 ; i < height ; ++i) { i_data = (void *)data + i * stride; remain = linesize; diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 6cc9f3367fa0..d410e2925162 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -85,6 +85,7 @@ static void apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info) { void *reloc_page; + reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK); *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev, info->src_bo, @@ -162,8 +163,7 @@ static int qxl_process_single_command(struct qxl_device *qdev, if (cmd->command_size > PAGE_SIZE - sizeof(union qxl_release_info)) return -EINVAL; - if (!access_ok(VERIFY_READ, - u64_to_user_ptr(cmd->command), + if (!access_ok(u64_to_user_ptr(cmd->command), cmd->command_size)) return -EFAULT; @@ -189,6 +189,7 @@ static int qxl_process_single_command(struct qxl_device *qdev, { struct qxl_drawable *draw = fb_cmd; + draw->mm_time = qdev->rom->mm_clock; } diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index e25c589d5f50..bee61fa2c9bc 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -26,7 +26,7 @@ #include "qxl_drv.h" #include "qxl_object.h" -#include <drm/drm_crtc_helper.h> +#include <drm/drm_probe_helper.h> #include <linux/io-mapping.h> int qxl_log_level; @@ -53,45 +53,53 @@ 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) +static void setup_hw_slot(struct qxl_device *qdev, 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); + qdev->ram_header->mem_slot.mem_end = slot->start_phys_addr + slot->size; + qxl_io_memslot_add(qdev, qdev->rom->slots_start + 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) +static void setup_slot(struct qxl_device *qdev, + struct qxl_memslot *slot, + unsigned int slot_index, + const char *slot_name, + unsigned long start_phys_addr, + unsigned long size) { uint64_t high_bits; - struct qxl_memslot *slot; - uint8_t slot_index; - slot_index = qdev->rom->slots_start + slot_index_offset; - slot = &qdev->mem_slots[slot_index]; + slot->index = slot_index; + slot->name = slot_name; slot->start_phys_addr = start_phys_addr; - slot->end_phys_addr = end_phys_addr; + slot->size = size; - setup_hw_slot(qdev, slot_index, slot); + setup_hw_slot(qdev, slot); slot->generation = qdev->rom->slot_generation; - high_bits = slot_index << qdev->slot_gen_bits; + high_bits = (qdev->rom->slots_start + slot->index) + << qdev->rom->slot_gen_bits; high_bits |= slot->generation; - high_bits <<= (64 - (qdev->slot_gen_bits + qdev->slot_id_bits)); + high_bits <<= (64 - (qdev->rom->slot_gen_bits + qdev->rom->slot_id_bits)); slot->high_bits = high_bits; - return slot_index; + + DRM_INFO("slot %d (%s): base 0x%08lx, size 0x%08lx, gpu_offset 0x%lx\n", + slot->index, slot->name, + (unsigned long)slot->start_phys_addr, + (unsigned long)slot->size, + (unsigned long)slot->gpu_offset); } 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]); + setup_hw_slot(qdev, &qdev->main_slot); + setup_hw_slot(qdev, &qdev->surfaces_slot); } static void qxl_gc_work(struct work_struct *work) { struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); + qxl_garbage_collect(qdev); } @@ -228,23 +236,6 @@ int qxl_device_init(struct qxl_device *qdev, r = -ENOMEM; goto cursor_ring_free; } - /* TODO - slot initialization should happen on reset. where is our - * reset handler? */ - qdev->n_mem_slots = qdev->rom->slots_end; - qdev->slot_gen_bits = qdev->rom->slot_gen_bits; - qdev->slot_id_bits = qdev->rom->slot_id_bits; - qdev->va_slot_mask = - (~(uint64_t)0) >> (qdev->slot_id_bits + qdev->slot_gen_bits); - - qdev->mem_slots = - kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot), - GFP_KERNEL); - - if (!qdev->mem_slots) { - DRM_ERROR("Unable to alloc mem slots\n"); - r = -ENOMEM; - goto release_ring_free; - } idr_init(&qdev->release_idr); spin_lock_init(&qdev->release_idr_lock); @@ -263,34 +254,24 @@ int qxl_device_init(struct qxl_device *qdev, r = qxl_irq_init(qdev); if (r) { DRM_ERROR("Unable to init qxl irq\n"); - goto mem_slots_free; + goto release_ring_free; } /* * Note that virtual is surface0. We rely on the single ioremap done * before. */ - qdev->main_mem_slot = setup_slot(qdev, 0, - (unsigned long)qdev->vram_base, - (unsigned long)qdev->vram_base + qdev->rom->ram_header_offset); - qdev->surfaces_mem_slot = setup_slot(qdev, 1, - (unsigned long)qdev->surfaceram_base, - (unsigned long)qdev->surfaceram_base + qdev->surfaceram_size); - DRM_INFO("main mem slot %d [%lx,%x]\n", - qdev->main_mem_slot, - (unsigned long)qdev->vram_base, qdev->rom->ram_header_offset); - DRM_INFO("surface mem slot %d [%lx,%lx]\n", - qdev->surfaces_mem_slot, - (unsigned long)qdev->surfaceram_base, - (unsigned long)qdev->surfaceram_size); - + setup_slot(qdev, &qdev->main_slot, 0, "main", + (unsigned long)qdev->vram_base, + (unsigned long)qdev->rom->ram_header_offset); + setup_slot(qdev, &qdev->surfaces_slot, 1, "surfaces", + (unsigned long)qdev->surfaceram_base, + (unsigned long)qdev->surfaceram_size); INIT_WORK(&qdev->gc_work, qxl_gc_work); return 0; -mem_slots_free: - kfree(qdev->mem_slots); release_ring_free: qxl_ring_free(qdev->release_ring); cursor_ring_free: @@ -313,10 +294,8 @@ error: void qxl_device_fini(struct qxl_device *qdev) { - if (qdev->current_release_bo[0]) - qxl_bo_unref(&qdev->current_release_bo[0]); - if (qdev->current_release_bo[1]) - qxl_bo_unref(&qdev->current_release_bo[1]); + qxl_bo_unref(&qdev->current_release_bo[0]); + qxl_bo_unref(&qdev->current_release_bo[1]); flush_work(&qdev->gc_work); qxl_ring_free(qdev->command_ring); qxl_ring_free(qdev->cursor_ring); diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 6a30196e9d6c..4928fa602944 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -36,6 +36,7 @@ static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo) qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; qxl_surface_evict(qdev, bo, false); + WARN_ON_ONCE(bo->map_count > 0); mutex_lock(&qdev->gem.mutex); list_del_init(&bo->list); mutex_unlock(&qdev->gem.mutex); @@ -54,14 +55,16 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned) { u32 c = 0; u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0; - unsigned i; + unsigned int i; qbo->placement.placement = qbo->placements; qbo->placement.busy_placement = qbo->placements; if (domain == QXL_GEM_DOMAIN_VRAM) qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag; - if (domain == QXL_GEM_DOMAIN_SURFACE) + if (domain == QXL_GEM_DOMAIN_SURFACE) { qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV | pflag; + qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag; + } if (domain == QXL_GEM_DOMAIN_CPU) qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag; if (!c) @@ -74,7 +77,6 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned) } } - int qxl_bo_create(struct qxl_device *qdev, unsigned long size, bool kernel, bool pinned, u32 domain, struct qxl_surface *surf, @@ -130,6 +132,7 @@ int qxl_bo_kmap(struct qxl_bo *bo, void **ptr) if (bo->kptr) { if (ptr) *ptr = bo->kptr; + bo->map_count++; return 0; } r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap); @@ -138,6 +141,7 @@ int qxl_bo_kmap(struct qxl_bo *bo, void **ptr) bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); if (ptr) *ptr = bo->kptr; + bo->map_count = 1; return 0; } @@ -179,6 +183,9 @@ void qxl_bo_kunmap(struct qxl_bo *bo) { if (bo->kptr == NULL) return; + bo->map_count--; + if (bo->map_count > 0) + return; bo->kptr = NULL; ttm_bo_kunmap(&bo->kmap); } @@ -187,13 +194,9 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *pmap) { struct ttm_mem_type_manager *man = &bo->tbo.bdev->man[bo->tbo.mem.mem_type]; - struct io_mapping *map; - if (bo->tbo.mem.mem_type == TTM_PL_VRAM) - map = qdev->vram_mapping; - else if (bo->tbo.mem.mem_type == TTM_PL_PRIV) - map = qdev->surface_mapping; - else + if ((bo->tbo.mem.mem_type != TTM_PL_VRAM) && + (bo->tbo.mem.mem_type != TTM_PL_PRIV)) goto fallback; io_mapping_unmap_atomic(pmap); @@ -201,7 +204,7 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, (void) ttm_mem_io_lock(man, false); ttm_mem_io_free(bo->tbo.bdev, &bo->tbo.mem); ttm_mem_io_unlock(man); - return ; + return; fallback: qxl_bo_kunmap(bo); } @@ -221,7 +224,7 @@ struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) return bo; } -static int __qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr) +static int __qxl_bo_pin(struct qxl_bo *bo) { struct ttm_operation_ctx ctx = { false, false }; struct drm_device *ddev = bo->gem_base.dev; @@ -229,16 +232,12 @@ static int __qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr) if (bo->pin_count) { bo->pin_count++; - if (gpu_addr) - *gpu_addr = qxl_bo_gpu_offset(bo); return 0; } - qxl_ttm_placement_from_domain(bo, domain, true); + qxl_ttm_placement_from_domain(bo, bo->type, true); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (likely(r == 0)) { bo->pin_count = 1; - if (gpu_addr != NULL) - *gpu_addr = qxl_bo_gpu_offset(bo); } if (unlikely(r != 0)) dev_err(ddev->dev, "%p pin failed\n", bo); @@ -266,13 +265,12 @@ static int __qxl_bo_unpin(struct qxl_bo *bo) return r; } - /* * Reserve the BO before pinning the object. If the BO was reserved * beforehand, use the internal version directly __qxl_bo_pin. * */ -int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr) +int qxl_bo_pin(struct qxl_bo *bo) { int r; @@ -280,7 +278,7 @@ int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr) if (r) return r; - r = __qxl_bo_pin(bo, bo->type, NULL); + r = __qxl_bo_pin(bo); qxl_bo_unreserve(bo); return r; } @@ -335,13 +333,14 @@ void qxl_bo_fini(struct qxl_device *qdev) int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo) { int ret; + if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) { /* allocate a surface id for this surface now */ ret = qxl_surface_id_alloc(qdev, bo); if (ret) return ret; - ret = qxl_hw_surface_alloc(qdev, bo, NULL); + ret = qxl_hw_surface_alloc(qdev, bo); if (ret) return ret; } diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index 0374fd93f4d6..255b914e2a7b 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -35,6 +35,7 @@ static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait) if (unlikely(r != 0)) { if (r != -ERESTARTSYS) { struct drm_device *ddev = bo->gem_base.dev; + dev_err(ddev->dev, "%p reserve failed\n", bo); } return r; @@ -71,6 +72,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type, if (unlikely(r != 0)) { if (r != -ERESTARTSYS) { struct drm_device *ddev = bo->gem_base.dev; + dev_err(ddev->dev, "%p reserve failed for wait\n", bo); } @@ -95,7 +97,7 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, int pa void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *map); extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo); extern void qxl_bo_unref(struct qxl_bo **bo); -extern int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr); +extern int qxl_bo_pin(struct qxl_bo *bo); extern int qxl_bo_unpin(struct qxl_bo *bo); extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned); extern bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo); diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c index 9f029dda1f07..114653b471c6 100644 --- a/drivers/gpu/drm/qxl/qxl_prime.c +++ b/drivers/gpu/drm/qxl/qxl_prime.c @@ -23,25 +23,27 @@ */ #include "qxl_drv.h" +#include "qxl_object.h" /* Empty Implementations as there should not be any other driver for a virtual * device that might share buffers with qxl */ int qxl_gem_prime_pin(struct drm_gem_object *obj) { - WARN_ONCE(1, "not implemented"); - return -ENOSYS; + struct qxl_bo *bo = gem_to_qxl_bo(obj); + + return qxl_bo_pin(bo); } void qxl_gem_prime_unpin(struct drm_gem_object *obj) { - WARN_ONCE(1, "not implemented"); -} + struct qxl_bo *bo = gem_to_qxl_bo(obj); + qxl_bo_unpin(bo); +} struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj) { - WARN_ONCE(1, "not implemented"); return ERR_PTR(-ENOSYS); } @@ -49,19 +51,27 @@ struct drm_gem_object *qxl_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *table) { - WARN_ONCE(1, "not implemented"); return ERR_PTR(-ENOSYS); } void *qxl_gem_prime_vmap(struct drm_gem_object *obj) { - WARN_ONCE(1, "not implemented"); - return ERR_PTR(-ENOSYS); + struct qxl_bo *bo = gem_to_qxl_bo(obj); + void *ptr; + int ret; + + ret = qxl_bo_kmap(bo, &ptr); + if (ret < 0) + return ERR_PTR(ret); + + return ptr; } void qxl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) { - WARN_ONCE(1, "not implemented"); + struct qxl_bo *bo = gem_to_qxl_bo(obj); + + qxl_bo_kunmap(bo); } int qxl_gem_prime_mmap(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index e37f0097f744..30f85f0130cb 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -217,7 +217,7 @@ int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo) qxl_bo_ref(bo); entry->tv.bo = &bo->tbo; - entry->tv.shared = false; + entry->tv.num_shared = 0; list_add_tail(&entry->tv.head, &release->bos); return 0; } @@ -234,7 +234,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo) return ret; } - ret = reservation_object_reserve_shared(bo->tbo.resv); + ret = reservation_object_reserve_shared(bo->tbo.resv, 1); if (ret) return ret; @@ -282,7 +282,6 @@ void qxl_release_backoff_reserve_list(struct qxl_release *release) ttm_eu_backoff_reservation(&release->ticket, &release->bos); } - int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, enum qxl_surface_cmd_type surface_cmd_type, struct qxl_release *create_rel, @@ -428,8 +427,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) struct ttm_buffer_object *bo; struct ttm_bo_global *glob; struct ttm_bo_device *bdev; - struct ttm_bo_driver *driver; - struct qxl_bo *qbo; struct ttm_validate_buffer *entry; struct qxl_device *qdev; @@ -450,14 +447,12 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) release->id | 0xf0000000, release->base.seqno); trace_dma_fence_emit(&release->base); - driver = bdev->driver; glob = bdev->glob; spin_lock(&glob->lru_lock); list_for_each_entry(entry, &release->bos, head) { bo = entry->bo; - qbo = to_qxl_bo(bo); reservation_object_add_shared_fence(bo->resv, &release->base); ttm_bo_add_to_lru(bo); diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 86a1fb32f6db..92f5db5b296f 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -46,62 +46,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) return qdev; } -static int qxl_ttm_mem_global_init(struct drm_global_reference *ref) -{ - return ttm_mem_global_init(ref->object); -} - -static void qxl_ttm_mem_global_release(struct drm_global_reference *ref) -{ - ttm_mem_global_release(ref->object); -} - -static int qxl_ttm_global_init(struct qxl_device *qdev) -{ - struct drm_global_reference *global_ref; - int r; - - qdev->mman.mem_global_referenced = false; - global_ref = &qdev->mman.mem_global_ref; - global_ref->global_type = DRM_GLOBAL_TTM_MEM; - global_ref->size = sizeof(struct ttm_mem_global); - global_ref->init = &qxl_ttm_mem_global_init; - global_ref->release = &qxl_ttm_mem_global_release; - - r = drm_global_item_ref(global_ref); - if (r != 0) { - DRM_ERROR("Failed setting up TTM memory accounting " - "subsystem.\n"); - return r; - } - - qdev->mman.bo_global_ref.mem_glob = - qdev->mman.mem_global_ref.object; - global_ref = &qdev->mman.bo_global_ref.ref; - global_ref->global_type = DRM_GLOBAL_TTM_BO; - global_ref->size = sizeof(struct ttm_bo_global); - global_ref->init = &ttm_bo_global_init; - global_ref->release = &ttm_bo_global_release; - r = drm_global_item_ref(global_ref); - if (r != 0) { - DRM_ERROR("Failed setting up TTM BO subsystem.\n"); - drm_global_item_unref(&qdev->mman.mem_global_ref); - return r; - } - - qdev->mman.mem_global_referenced = true; - return 0; -} - -static void qxl_ttm_global_fini(struct qxl_device *qdev) -{ - if (qdev->mman.mem_global_referenced) { - drm_global_item_unref(&qdev->mman.bo_global_ref.ref); - drm_global_item_unref(&qdev->mman.mem_global_ref); - qdev->mman.mem_global_referenced = false; - } -} - static struct vm_operations_struct qxl_ttm_vm_ops; static const struct vm_operations_struct *ttm_vm_ops; @@ -156,6 +100,11 @@ static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man) { + struct qxl_device *qdev = qxl_get_qdev(bdev); + unsigned int gpu_offset_shift = + 64 - (qdev->rom->slot_gen_bits + qdev->rom->slot_id_bits + 8); + struct qxl_memslot *slot; + switch (type) { case TTM_PL_SYSTEM: /* System memory */ @@ -166,15 +115,18 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, case TTM_PL_VRAM: case TTM_PL_PRIV: /* "On-card" video ram */ + slot = (type == TTM_PL_VRAM) ? + &qdev->main_slot : &qdev->surfaces_slot; + slot->gpu_offset = (uint64_t)type << gpu_offset_shift; man->func = &ttm_bo_manager_func; - man->gpu_offset = 0; + man->gpu_offset = slot->gpu_offset; man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; break; default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); return -EINVAL; } return 0; @@ -252,7 +204,7 @@ static void qxl_ttm_io_mem_free(struct ttm_bo_device *bdev, * TTM backend functions. */ struct qxl_ttm_tt { - struct ttm_dma_tt ttm; + struct ttm_tt ttm; struct qxl_device *qdev; u64 offset; }; @@ -281,7 +233,7 @@ static void qxl_ttm_backend_destroy(struct ttm_tt *ttm) { struct qxl_ttm_tt *gtt = (void *)ttm; - ttm_dma_tt_fini(>t->ttm); + ttm_tt_fini(>t->ttm); kfree(gtt); } @@ -301,13 +253,13 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo, gtt = kzalloc(sizeof(struct qxl_ttm_tt), GFP_KERNEL); if (gtt == NULL) return NULL; - gtt->ttm.ttm.func = &qxl_backend_func; + gtt->ttm.func = &qxl_backend_func; gtt->qdev = qdev; - if (ttm_dma_tt_init(>t->ttm, bo, page_flags)) { + if (ttm_tt_init(>t->ttm, bo, page_flags)) { kfree(gtt); return NULL; } - return >t->ttm.ttm; + return >t->ttm; } static void qxl_move_null(struct ttm_buffer_object *bo, @@ -331,7 +283,6 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, if (ret) return ret; - if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { qxl_move_null(bo, new_mem); return 0; @@ -373,12 +324,8 @@ int qxl_ttm_init(struct qxl_device *qdev) int r; int num_io_pages; /* != rom->num_io_pages, we include surface0 */ - r = qxl_ttm_global_init(qdev); - if (r) - return r; /* No others user of address space so set it to 0 */ r = ttm_bo_device_init(&qdev->mman.bdev, - qdev->mman.bo_global_ref.ref.object, &qxl_bo_driver, qdev->ddev.anon_inode->i_mapping, DRM_FILE_PAGE_OFFSET, 0); @@ -401,11 +348,11 @@ int qxl_ttm_init(struct qxl_device *qdev) return r; } DRM_INFO("qxl: %uM of VRAM memory size\n", - (unsigned)qdev->vram_size / (1024 * 1024)); + (unsigned int)qdev->vram_size / (1024 * 1024)); DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n", - ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); + ((unsigned int)num_io_pages * PAGE_SIZE) / (1024 * 1024)); DRM_INFO("qxl: %uM of Surface memory size\n", - (unsigned)qdev->surfaceram_size / (1024 * 1024)); + (unsigned int)qdev->surfaceram_size / (1024 * 1024)); return 0; } @@ -414,11 +361,9 @@ void qxl_ttm_fini(struct qxl_device *qdev) ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV); ttm_bo_device_release(&qdev->mman.bdev); - qxl_ttm_global_fini(qdev); DRM_INFO("qxl: ttm finalized\n"); } - #define QXL_DEBUGFS_MEM_TYPES 2 #if defined(CONFIG_DEBUG_FS) @@ -443,7 +388,7 @@ int qxl_ttm_debugfs_init(struct qxl_device *qdev) #if defined(CONFIG_DEBUG_FS) static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32]; - unsigned i; + unsigned int i; for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) { if (i == 0) |