int qxl_garbage_collect(struct qxl_device *qdev) { struct qxl_release *release; uint64_t id, next_id; int i = 0; int ret; union qxl_release_info *info; while (qxl_ring_pop(qdev->release_ring, &id)) { QXL_INFO(qdev, "popped %lld\n", id); while (id) { release = qxl_release_from_id_locked(qdev, id); if (release == NULL) break; ret = qxl_release_reserve(qdev, release, false); if (ret) { qxl_io_log(qdev, "failed to reserve release on garbage collect %lld\n", id); DRM_ERROR("failed to reserve release %lld\n", id); } info = qxl_release_map(qdev, release); next_id = info->next; qxl_release_unmap(qdev, release, info); qxl_release_unreserve(qdev, release); QXL_INFO(qdev, "popped %lld, next %lld\n", id, next_id); switch (release->type) { case QXL_RELEASE_DRAWABLE: case QXL_RELEASE_SURFACE_CMD: case QXL_RELEASE_CURSOR_CMD: break; default: DRM_ERROR("unexpected release type\n"); break; } id = next_id; qxl_release_free(qdev, release); ++i; } } QXL_INFO(qdev, "%s: %lld\n", __func__, i); return i; }
int qxl_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv; struct qxl_device *qdev; int r; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { pr_info("%s: vma->vm_pgoff (%ld) < DRM_FILE_PAGE_OFFSET\n", __func__, vma->vm_pgoff); return -EINVAL; } file_priv = filp->private_data; qdev = file_priv->minor->dev->dev_private; if (qdev == NULL) { DRM_ERROR( "filp->private_data->minor->dev->dev_private == NULL\n"); return -EINVAL; } QXL_INFO(qdev, "%s: filp->private_data = 0x%p, vma->vm_pgoff = %lx\n", __func__, filp->private_data, vma->vm_pgoff); r = ttm_bo_mmap(filp, vma, &qdev->mman.bdev); if (unlikely(r != 0)) return r; if (unlikely(ttm_vm_ops == NULL)) { ttm_vm_ops = vma->vm_ops; qxl_ttm_vm_ops = *ttm_vm_ops; qxl_ttm_vm_ops.fault = &qxl_ttm_fault; } vma->vm_ops = &qxl_ttm_vm_ops; return 0; }
void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, unsigned height, unsigned offset, struct qxl_bo *bo) { struct qxl_surface_create *create; QXL_INFO(qdev, "%s: qdev %p, ram_header %p\n", __func__, qdev, qdev->ram_header); create = &qdev->ram_header->create_surface; create->format = bo->surf.format; create->width = width; create->height = height; create->stride = bo->surf.stride; create->mem = qxl_bo_physical_address(qdev, bo, offset); QXL_INFO(qdev, "%s: mem = %llx, from %p\n", __func__, create->mem, bo->kptr); create->flags = QXL_SURF_FLAG_KEEP_DATA; create->type = QXL_SURF_TYPE_PRIMARY; wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); }
static int qxlfb_create(struct qxl_fbdev *qfbdev, struct drm_fb_helper_surface_size *sizes) { struct qxl_device *qdev = qfbdev->qdev; 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 size; 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(qfbdev, &mode_cmd, &gobj); if (ret < 0) return ret; qbo = gem_to_qxl_bo(gobj); QXL_INFO(qdev, "%s: %dx%d %d\n", __func__, mode_cmd.width, mode_cmd.height, mode_cmd.pitches[0]); shadow = vmalloc(mode_cmd.pitches[0] * mode_cmd.height); /* TODO: what's the usual response to memory allocation errors? */ BUG_ON(!shadow); QXL_INFO(qdev, "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); size = mode_cmd.pitches[0] * mode_cmd.height; info = drm_fb_helper_alloc_fbi(&qfbdev->helper); if (IS_ERR(info)) { ret = PTR_ERR(info); goto out_unref; } info->par = qfbdev; qxl_framebuffer_init(qdev->ddev, &qfbdev->qfb, &mode_cmd, gobj, &qxlfb_fb_funcs); fb = &qfbdev->qfb.base; /* setup helper with fb data */ qfbdev->helper.fb = fb; qfbdev->shadow = shadow; strcpy(info->fix.id, "qxldrmfb"); drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; 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 = qfbdev->shadow; info->screen_size = gobj->size; drm_fb_helper_fill_var(info, &qfbdev->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_destroy_fbi; } info->fbdefio = &qxl_defio; fb_deferred_io_init(info); qdev->fbdev_info = info; qdev->fbdev_qfb = &qfbdev->qfb; 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->depth, fb->pitches[0], fb->width, fb->height); return 0; out_destroy_fbi: drm_fb_helper_release_fbi(&qfbdev->helper); out_unref: if (qbo) { ret = qxl_bo_reserve(qbo, false); if (likely(ret == 0)) { qxl_bo_kunmap(qbo); qxl_bo_unpin(qbo); qxl_bo_unreserve(qbo); } } if (fb && ret) { drm_gem_object_unreference_unlocked(gobj); drm_framebuffer_cleanup(fb); kfree(fb); } drm_gem_object_unreference_unlocked(gobj); return ret; }
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) { QXL_INFO(qdev, "qxl_memslot_add %d\n", id); wait_for_io_cmd(qdev, id, QXL_IO_MEMSLOT_ADD_ASYNC); }