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 | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_display.c | 340 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_draw.c | 241 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_drv.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_drv.h | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_dumb.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_fb.c | 300 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_kms.c | 83 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_object.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_prime.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_ttm.c | 20 |
12 files changed, 319 insertions, 812 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 dffc5093ff16..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" @@ -372,25 +374,25 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev) 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 int 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); @@ -398,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) @@ -458,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; @@ -485,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_display.c b/drivers/gpu/drm/qxl/qxl_display.c index ce0b9c40fc21..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,60 +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 int pwidth, - unsigned int 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; + int i, ret = 0; - 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; + 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) @@ -302,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; @@ -323,6 +332,8 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, 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; @@ -348,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); } @@ -401,13 +413,15 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, 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; } @@ -424,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); @@ -466,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) @@ -526,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]); @@ -542,32 +550,21 @@ static void qxl_primary_atomic_update(struct drm_plane *plane, bo_old = NULL; } - if (bo == bo_old) - return; + primary = bo->shadow ? bo->shadow : bo; - if (bo_old && bo_old->shadow && bo->shadow && - bo_old->shadow == bo->shadow) { - same_shadow = true; - } - - 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, @@ -723,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) @@ -738,28 +791,30 @@ 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; } } @@ -788,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; } @@ -925,14 +980,26 @@ free_mem: static int qxl_conn_get_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); 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; } @@ -941,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) @@ -1010,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, @@ -1097,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, @@ -1121,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; } @@ -1173,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 c408bb83c7a9..97c3f1a95a32 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -109,152 +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: - 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. * @@ -267,7 +121,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, struct qxl_bo *bo, unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned int 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 @@ -295,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; @@ -342,7 +200,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, 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 ccb090f3ab30..bb81e310eb6d 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" @@ -93,6 +94,8 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto modeset_cleanup; + drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "qxl"); + drm_fbdev_generic_setup(&qdev->ddev, 32); return 0; modeset_cleanup: @@ -242,7 +245,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 13a0254b59a1..4a0331b3ff7d 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -84,6 +84,7 @@ struct qxl_bo { struct ttm_bo_kmap_obj kmap; unsigned int pin_count; void *kptr; + unsigned int map_count; int type; /* Constant after initialization */ @@ -130,10 +131,13 @@ struct qxl_mman { }; 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 { @@ -216,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; @@ -226,16 +228,12 @@ struct qxl_device { struct qxl_ram_header *ram_header; - unsigned int primary_created:1; - - 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; @@ -308,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); @@ -392,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 int 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); @@ -437,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 int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned int 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); @@ -485,9 +463,6 @@ 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 int nfiles); @@ -497,8 +472,7 @@ int qxl_surface_id_alloc(struct qxl_device *qdev, 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 e3765739c396..272d19b677d8 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c @@ -59,7 +59,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv, 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 a819d24225d2..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); - 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 int flags, unsigned int color, - struct drm_clip_rect *clips, - unsigned int 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_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 15238a413f9d..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,40 +53,47 @@ 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) @@ -229,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); @@ -264,33 +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: diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 91f3bbc73ecc..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); @@ -60,8 +61,10 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned) 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) @@ -129,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); @@ -137,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; } @@ -178,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); } @@ -332,7 +340,7 @@ int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *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_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c index df65d3c1a7b8..8b448eca1cd9 100644 --- a/drivers/gpu/drm/qxl/qxl_prime.c +++ b/drivers/gpu/drm/qxl/qxl_prime.c @@ -23,30 +23,43 @@ */ #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); } 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_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 886f61e94f24..92f5db5b296f 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -100,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 */ @@ -110,8 +115,11 @@ 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; @@ -196,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; }; @@ -225,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); } @@ -245,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, |