Ejemplo n.º 1
0
int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf,
			const struct qxl_rect *area)
{
	int surface_id;
	uint32_t surface_width, surface_height;
	int ret;

	if (!surf->hw_surf_alloc)
		DRM_ERROR("got io update area with no hw surface\n");

	if (surf->is_primary)
		surface_id = 0;
	else
		surface_id = surf->surface_id;
	surface_width = surf->surf.width;
	surface_height = surf->surf.height;

	if (area->left < 0 || area->top < 0 ||
	    area->right > surface_width || area->bottom > surface_height) {
		qxl_io_log(qdev, "%s: not doing area update for "
			   "%d, (%d,%d,%d,%d) (%d,%d)\n", __func__, surface_id, area->left,
			   area->top, area->right, area->bottom, surface_width, surface_height);
		return -EINVAL;
	}
	mutex_lock(&qdev->update_area_mutex);
	qdev->ram_header->update_area = *area;
	qdev->ram_header->update_surface = surface_id;
	ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true);
	mutex_unlock(&qdev->update_area_mutex);
	return ret;
}
Ejemplo n.º 2
0
void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
{

	while (qxl_display_copy_rom_client_monitors_config(qdev)) {
		qxl_io_log(qdev, "failed crc check for client_monitors_config,"
				 " retrying\n");
	}
	drm_helper_hpd_irq_event(qdev->ddev);
}
Ejemplo n.º 3
0
irqreturn_t qxl_irq_handler(int irq, void *arg)
{
	struct drm_device *dev = (struct drm_device *) arg;
	struct qxl_device *qdev = (struct qxl_device *)dev->dev_private;
	uint32_t pending;

	pending = xchg(&qdev->ram_header->int_pending, 0);

	if (!pending)
		return IRQ_NONE;

	atomic_inc(&qdev->irq_received);

	if (pending & QXL_INTERRUPT_DISPLAY) {
		atomic_inc(&qdev->irq_received_display);
		wake_up_all(&qdev->display_event);
		qxl_queue_garbage_collect(qdev, false);
	}
	if (pending & QXL_INTERRUPT_CURSOR) {
		atomic_inc(&qdev->irq_received_cursor);
		wake_up_all(&qdev->cursor_event);
	}
	if (pending & QXL_INTERRUPT_IO_CMD) {
		atomic_inc(&qdev->irq_received_io_cmd);
		wake_up_all(&qdev->io_cmd_event);
	}
	if (pending & QXL_INTERRUPT_ERROR) {
		/* TODO: log it, reset device (only way to exit this condition)
		 * (do it a certain number of times, afterwards admit defeat,
		 * to avoid endless loops).
		 */
		qdev->irq_received_error++;
		qxl_io_log(qdev, "%s: driver is in bug mode.\n", __func__);
	}
	if (pending & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) {
		qxl_io_log(qdev, "QXL_INTERRUPT_CLIENT_MONITORS_CONFIG\n");
		schedule_work(&qdev->client_monitors_config_work);
	}
	qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
	outb(0, qdev->io_base + QXL_IO_UPDATE_IRQ);
	return IRQ_HANDLED;
}
Ejemplo n.º 4
0
static bool qxl_crtc_mode_fixup(struct drm_crtc *crtc,
				  const struct drm_display_mode *mode,
				  struct drm_display_mode *adjusted_mode)
{
	struct drm_device *dev = crtc->dev;
	struct qxl_device *qdev = dev->dev_private;

	qxl_io_log(qdev, "%s: (%d,%d) => (%d,%d)\n",
		   __func__,
		   mode->hdisplay, mode->vdisplay,
		   adjusted_mode->hdisplay,
		   adjusted_mode->vdisplay);
	return true;
}
Ejemplo n.º 5
0
void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
{

	while (qxl_display_copy_rom_client_monitors_config(qdev)) {
		qxl_io_log(qdev, "failed crc check for client_monitors_config,"
				 " retrying\n");
	}

	if (!drm_helper_hpd_irq_event(qdev->ddev)) {
		/* notify that the monitor configuration changed, to
		   adjust at the arbitrary resolution */
		drm_kms_helper_hotplug_event(qdev->ddev);
	}
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
void qxl_io_monitors_config(struct qxl_device *qdev)
{
	qxl_io_log(qdev, "%s: %d [%dx%d+%d+%d]\n", __func__,
		   qdev->monitors_config ?
		   qdev->monitors_config->count : -1,
		   qdev->monitors_config && qdev->monitors_config->count ?
		   qdev->monitors_config->heads[0].width : -1,
		   qdev->monitors_config && qdev->monitors_config->count ?
		   qdev->monitors_config->heads[0].height : -1,
		   qdev->monitors_config && qdev->monitors_config->count ?
		   qdev->monitors_config->heads[0].x : -1,
		   qdev->monitors_config && qdev->monitors_config->count ?
		   qdev->monitors_config->heads[0].y : -1
		   );

	wait_for_io_cmd(qdev, 0, QXL_IO_MONITORS_CONFIG_ASYNC);
}
Ejemplo n.º 8
0
static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
{
	int i;
	int num_monitors;
	uint32_t crc;

	num_monitors = qdev->rom->client_monitors_config.count;
	crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config,
		  sizeof(qdev->rom->client_monitors_config));
	if (crc != qdev->rom->client_monitors_config_crc) {
		qxl_io_log(qdev, "crc mismatch: have %X (%d) != %X\n", crc,
			   sizeof(qdev->rom->client_monitors_config),
			   qdev->rom->client_monitors_config_crc);
		return 1;
	}
	if (num_monitors > qdev->monitors_config->max_allowed) {
		DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
			      qdev->monitors_config->max_allowed, num_monitors);
		num_monitors = qdev->monitors_config->max_allowed;
	} else {
		num_monitors = qdev->rom->client_monitors_config.count;
	}
	qxl_alloc_client_monitors_config(qdev, num_monitors);
	/* we copy max from the client but it isn't used */
	qdev->client_monitors_config->max_allowed =
				qdev->monitors_config->max_allowed;
	for (i = 0 ; i < qdev->client_monitors_config->count ; ++i) {
		struct qxl_urect *c_rect =
			&qdev->rom->client_monitors_config.heads[i];
		struct qxl_head *client_head =
			&qdev->client_monitors_config->heads[i];
		client_head->x = c_rect->left;
		client_head->y = c_rect->top;
		client_head->width = c_rect->right - c_rect->left;
		client_head->height = c_rect->bottom - c_rect->top;
		client_head->surface_id = 0;
		client_head->id = i;
		client_head->flags = 0;
		DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head->width, client_head->height,
			  client_head->x, client_head->y);
	}
	return 0;
}
Ejemplo n.º 9
0
static void qxl_fb_dirty_flush(struct fb_info *info)
{
	struct qxl_fbdev *qfbdev = info->par;
	struct qxl_device *qdev = qfbdev->qdev;
	struct qxl_fb_image qxl_fb_image;
	struct fb_image *image = &qxl_fb_image.fb_image;
	u32 x1, x2, y1, y2;

	/* TODO: hard coding 32 bpp */
	int stride = qfbdev->qfb.base.pitches[0] * 4;

	x1 = qfbdev->dirty.x1;
	x2 = qfbdev->dirty.x2;
	y1 = qfbdev->dirty.y1;
	y2 = qfbdev->dirty.y2;
	/*
	 * we are using a shadow draw buffer, at qdev->surface0_shadow
	 */
	qxl_io_log(qdev, "dirty x[%d, %d], y[%d, %d]", x1, x2, y1, y2);
	image->dx = x1;
	image->dy = y1;
	image->width = x2 - x1;
	image->height = y2 - 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 = qfbdev->shadow + (x1 * 4) + (stride * y1);

	qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL);
	qxl_draw_opaque_fb(&qxl_fb_image, stride);
	qfbdev->dirty.x1 = 0;
	qfbdev->dirty.x2 = 0;
	qfbdev->dirty.y1 = 0;
	qfbdev->dirty.y2 = 0;
}
Ejemplo n.º 10
0
void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count)
{
	if (qdev->client_monitors_config &&
	    count > qdev->client_monitors_config->count) {
		kfree(qdev->client_monitors_config);
		qdev->client_monitors_config = NULL;
	}
	if (!qdev->client_monitors_config) {
		qdev->client_monitors_config = kzalloc(
				sizeof(struct qxl_monitors_config) +
				sizeof(struct qxl_head) * count, GFP_KERNEL);
		if (!qdev->client_monitors_config) {
			qxl_io_log(qdev,
				   "%s: allocation failure for %u heads\n",
				   __func__, count);
			return;
		}
	}
	qdev->client_monitors_config->count = count;
}
Ejemplo n.º 11
0
/*
 * 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->fbdev_info;
	struct qxl_fbdev *qfbdev = info->par;
	struct qxl_fb_image qxl_fb_image;
	struct fb_image *image = &qxl_fb_image.fb_image;

	/* TODO: hard coding 32 bpp */
	int stride = qfbdev->qfb.base.pitches[0];

	/*
	 * we are using a shadow draw buffer, at qdev->surface0_shadow
	 */
	qxl_io_log(qdev, "dirty x[%d, %d], y[%d, %d]", clips->x1, clips->x2,
		   clips->y1, clips->y2);
	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 = qfbdev->shadow + (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;
}
Ejemplo n.º 12
0
void
qxl_send_monitors_config(struct qxl_device *qdev)
{
	int i;

	BUG_ON(!qdev->ram_header->monitors_config);

	if (qdev->monitors_config->count == 0) {
		qxl_io_log(qdev, "%s: 0 monitors??\n", __func__);
		return;
	}
	for (i = 0 ; i < qdev->monitors_config->count ; ++i) {
		struct qxl_head *head = &qdev->monitors_config->heads[i];

		if (head->y > 8192 || head->x > 8192 ||
		    head->width > 8192 || head->height > 8192) {
			DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
				  i, head->width, head->height,
				  head->x, head->y);
			return;
		}
	}
	qxl_io_monitors_config(qdev);
}
Ejemplo n.º 13
0
static int qxl_crtc_mode_set(struct drm_crtc *crtc,
			       struct drm_display_mode *mode,
			       struct drm_display_mode *adjusted_mode,
			       int x, int y,
			       struct drm_framebuffer *old_fb)
{
	struct drm_device *dev = crtc->dev;
	struct qxl_device *qdev = dev->dev_private;
	struct qxl_mode *m = (void *)mode->private;
	struct qxl_framebuffer *qfb;
	struct qxl_bo *bo, *old_bo = NULL;
	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
	uint32_t width, height, base_offset;
	bool recreate_primary = false;
	int ret;
	int surf_id;
	if (!crtc->fb) {
		DRM_DEBUG_KMS("No FB bound\n");
		return 0;
	}

	if (old_fb) {
		qfb = to_qxl_framebuffer(old_fb);
		old_bo = gem_to_qxl_bo(qfb->obj);
	}
	qfb = to_qxl_framebuffer(crtc->fb);
	bo = gem_to_qxl_bo(qfb->obj);
	if (!m)
		/* and do we care? */
		DRM_DEBUG("%dx%d: not a native mode\n", x, y);
	else
		DRM_DEBUG("%dx%d: qxl id %d\n",
			  mode->hdisplay, mode->vdisplay, m->id);
	DRM_DEBUG("+%d+%d (%d,%d) => (%d,%d)\n",
		  x, y,
		  mode->hdisplay, mode->vdisplay,
		  adjusted_mode->hdisplay,
		  adjusted_mode->vdisplay);

	if (qcrtc->index == 0)
		recreate_primary = true;

	width = mode->hdisplay;
	height = mode->vdisplay;
	base_offset = 0;

	ret = qxl_bo_reserve(bo, false);
	if (ret != 0)
		return ret;
	ret = qxl_bo_pin(bo, bo->type, NULL);
	if (ret != 0) {
		qxl_bo_unreserve(bo);
		return -EINVAL;
	}
	qxl_bo_unreserve(bo);
	if (recreate_primary) {
		qxl_io_destroy_primary(qdev);
		qxl_io_log(qdev,
			   "recreate primary: %dx%d (was %dx%d,%d,%d)\n",
			   width, height, bo->surf.width,
			   bo->surf.height, bo->surf.stride, bo->surf.format);
		qxl_io_create_primary(qdev, base_offset, bo);
		bo->is_primary = true;
		surf_id = 0;
	} else {
		surf_id = bo->surface_id;
	}

	if (old_bo && old_bo != bo) {
		old_bo->is_primary = false;
		ret = qxl_bo_reserve(old_bo, false);
		qxl_bo_unpin(old_bo);
		qxl_bo_unreserve(old_bo);
	}

	qxl_monitors_config_set(qdev, qcrtc->index, x, y,
				mode->hdisplay,
				mode->vdisplay, surf_id);
	return 0;
}