lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8132411b-ee50-fe42-2e62-8816a1f85433@gmail.com>
Date:   Mon, 5 Mar 2018 14:59:23 +0200
From:   Oleksandr Andrushchenko <andr2000@...il.com>
To:     xen-devel@...ts.xenproject.org, linux-kernel@...r.kernel.org,
        dri-devel@...ts.freedesktop.org, airlied@...ux.ie,
        daniel.vetter@...el.com, seanpaul@...omium.org,
        gustavo@...ovan.org, jgross@...e.com, boris.ostrovsky@...cle.com,
        konrad.wilk@...cle.com,
        Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
Subject: Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

On 03/05/2018 11:23 AM, Daniel Vetter wrote:
> On Wed, Feb 21, 2018 at 10:03:40AM +0200, Oleksandr Andrushchenko wrote:
>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
>>
>> Implement kernel modesetiing/connector handling using
>> DRM simple KMS helper pipeline:
>>
>> - implement KMS part of the driver with the help of DRM
>>    simple pipepline helper which is possible due to the fact
>>    that the para-virtualized driver only supports a single
>>    (primary) plane:
>>    - initialize connectors according to XenStore configuration
>>    - handle frame done events from the backend
>>    - generate vblank events
>>    - create and destroy frame buffers and propagate those
>>      to the backend
>>    - propagate set/reset mode configuration to the backend on display
>>      enable/disable callbacks
>>    - send page flip request to the backend and implement logic for
>>      reporting backend IO errors on prepare fb callback
>>
>> - implement virtual connector handling:
>>    - support only pixel formats suitable for single plane modes
>>    - make sure the connector is always connected
>>    - support a single video mode as per para-virtualized driver
>>      configuration
>>
>> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
> I think once you've removed the midlayer in the previous patch it would
> makes sense to merge the 2 patches into 1.
ok, will squash the two
>
> Bunch more comments below.
> -Daniel
>
>> ---
>>   drivers/gpu/drm/xen/Makefile             |   2 +
>>   drivers/gpu/drm/xen/xen_drm_front_conn.c | 125 +++++++++++++
>>   drivers/gpu/drm/xen/xen_drm_front_conn.h |  35 ++++
>>   drivers/gpu/drm/xen/xen_drm_front_drv.c  |  15 ++
>>   drivers/gpu/drm/xen/xen_drm_front_drv.h  |  12 ++
>>   drivers/gpu/drm/xen/xen_drm_front_kms.c  | 299 +++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/xen/xen_drm_front_kms.h  |  30 ++++
>>   7 files changed, 518 insertions(+)
>>   create mode 100644 drivers/gpu/drm/xen/xen_drm_front_conn.c
>>   create mode 100644 drivers/gpu/drm/xen/xen_drm_front_conn.h
>>   create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.c
>>   create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.h
>>
>> diff --git a/drivers/gpu/drm/xen/Makefile b/drivers/gpu/drm/xen/Makefile
>> index d3068202590f..4fcb0da1a9c5 100644
>> --- a/drivers/gpu/drm/xen/Makefile
>> +++ b/drivers/gpu/drm/xen/Makefile
>> @@ -2,6 +2,8 @@
>>   
>>   drm_xen_front-objs := xen_drm_front.o \
>>   		      xen_drm_front_drv.o \
>> +		      xen_drm_front_kms.o \
>> +		      xen_drm_front_conn.o \
>>   		      xen_drm_front_evtchnl.o \
>>   		      xen_drm_front_shbuf.o \
>>   		      xen_drm_front_cfg.o
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_conn.c b/drivers/gpu/drm/xen/xen_drm_front_conn.c
>> new file mode 100644
>> index 000000000000..d9986a2e1a3b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_conn.c
>> @@ -0,0 +1,125 @@
>> +/*
>> + *  Xen para-virtual DRM device
>> + *
>> + *   This program is free software; you can redistribute it and/or modify
>> + *   it under the terms of the GNU General Public License as published by
>> + *   the Free Software Foundation; either version 2 of the License, or
>> + *   (at your option) any later version.
>> + *
>> + *   This program is distributed in the hope that it will be useful,
>> + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *   GNU General Public License for more details.
>> + *
>> + * Copyright (C) 2016-2018 EPAM Systems Inc.
>> + *
>> + * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc_helper.h>
>> +
>> +#include <video/videomode.h>
>> +
>> +#include "xen_drm_front_conn.h"
>> +#include "xen_drm_front_drv.h"
>> +
>> +static struct xen_drm_front_drm_pipeline *
>> +to_xen_drm_pipeline(struct drm_connector *connector)
>> +{
>> +	return container_of(connector, struct xen_drm_front_drm_pipeline, conn);
>> +}
>> +
>> +static const uint32_t plane_formats[] = {
>> +	DRM_FORMAT_RGB565,
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +	DRM_FORMAT_ARGB8888,
>> +	DRM_FORMAT_XRGB4444,
>> +	DRM_FORMAT_ARGB4444,
>> +	DRM_FORMAT_XRGB1555,
>> +	DRM_FORMAT_ARGB1555,
>> +};
>> +
>> +const uint32_t *xen_drm_front_conn_get_formats(int *format_count)
>> +{
>> +	*format_count = ARRAY_SIZE(plane_formats);
>> +	return plane_formats;
>> +}
>> +
>> +static enum drm_connector_status connector_detect(
>> +		struct drm_connector *connector, bool force)
>> +{
>> +	if (drm_dev_is_unplugged(connector->dev))
>> +		return connector_status_disconnected;
>> +
>> +	return connector_status_connected;
>> +}
>> +
>> +#define XEN_DRM_NUM_VIDEO_MODES		1
>> +#define XEN_DRM_CRTC_VREFRESH_HZ	60
>> +
>> +static int connector_get_modes(struct drm_connector *connector)
>> +{
>> +	struct xen_drm_front_drm_pipeline *pipeline =
>> +		to_xen_drm_pipeline(connector);
>> +	struct drm_display_mode *mode;
>> +	struct videomode videomode;
>> +	int width, height;
>> +
>> +	mode = drm_mode_create(connector->dev);
>> +	if (!mode)
>> +		return 0;
>> +
>> +	memset(&videomode, 0, sizeof(videomode));
>> +	videomode.hactive = pipeline->width;
>> +	videomode.vactive = pipeline->height;
>> +	width = videomode.hactive + videomode.hfront_porch +
>> +		videomode.hback_porch + videomode.hsync_len;
>> +	height = videomode.vactive + videomode.vfront_porch +
>> +		videomode.vback_porch + videomode.vsync_len;
>> +	videomode.pixelclock = width * height * XEN_DRM_CRTC_VREFRESH_HZ;
>> +	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
>> +
>> +	drm_display_mode_from_videomode(&videomode, mode);
>> +	drm_mode_probed_add(connector, mode);
>> +	return XEN_DRM_NUM_VIDEO_MODES;
>> +}
>> +
>> +static int connector_mode_valid(struct drm_connector *connector,
>> +		struct drm_display_mode *mode)
>> +{
>> +	struct xen_drm_front_drm_pipeline *pipeline =
>> +			to_xen_drm_pipeline(connector);
>> +
>> +	if (mode->hdisplay != pipeline->width)
>> +		return MODE_ERROR;
>> +
>> +	if (mode->vdisplay != pipeline->height)
>> +		return MODE_ERROR;
>> +
>> +	return MODE_OK;
>> +}
>> +
>> +static const struct drm_connector_helper_funcs connector_helper_funcs = {
>> +	.get_modes = connector_get_modes,
>> +	.mode_valid = connector_mode_valid,
>> +};
>> +
>> +static const struct drm_connector_funcs connector_funcs = {
>> +	.detect = connector_detect,
>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>> +	.destroy = drm_connector_cleanup,
>> +	.reset = drm_atomic_helper_connector_reset,
>> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> +};
>> +
>> +int xen_drm_front_conn_init(struct xen_drm_front_drm_info *drm_info,
>> +		struct drm_connector *connector)
>> +{
>> +	drm_connector_helper_add(connector, &connector_helper_funcs);
>> +
>> +	return drm_connector_init(drm_info->drm_dev, connector,
>> +		&connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
>> +}
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_conn.h b/drivers/gpu/drm/xen/xen_drm_front_conn.h
>> new file mode 100644
>> index 000000000000..708e80d45985
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_conn.h
>> @@ -0,0 +1,35 @@
>> +/*
>> + *  Xen para-virtual DRM device
>> + *
>> + *   This program is free software; you can redistribute it and/or modify
>> + *   it under the terms of the GNU General Public License as published by
>> + *   the Free Software Foundation; either version 2 of the License, or
>> + *   (at your option) any later version.
>> + *
>> + *   This program is distributed in the hope that it will be useful,
>> + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *   GNU General Public License for more details.
>> + *
>> + * Copyright (C) 2016-2018 EPAM Systems Inc.
>> + *
>> + * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
>> + */
>> +
>> +#ifndef __XEN_DRM_FRONT_CONN_H_
>> +#define __XEN_DRM_FRONT_CONN_H_
>> +
>> +#include <drm/drmP.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_encoder.h>
>> +
>> +#include <linux/wait.h>
>> +
>> +struct xen_drm_front_drm_info;
>> +
>> +const uint32_t *xen_drm_front_conn_get_formats(int *format_count);
>> +
>> +int xen_drm_front_conn_init(struct xen_drm_front_drm_info *drm_info,
>> +		struct drm_connector *connector);
>> +
>> +#endif /* __XEN_DRM_FRONT_CONN_H_ */
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_drv.c b/drivers/gpu/drm/xen/xen_drm_front_drv.c
>> index b3764d5ed0f6..e8862d26ba27 100644
>> --- a/drivers/gpu/drm/xen/xen_drm_front_drv.c
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_drv.c
>> @@ -23,6 +23,7 @@
>>   #include "xen_drm_front.h"
>>   #include "xen_drm_front_cfg.h"
>>   #include "xen_drm_front_drv.h"
>> +#include "xen_drm_front_kms.h"
>>   
>>   static int dumb_create(struct drm_file *filp,
>>   		struct drm_device *dev, struct drm_mode_create_dumb *args)
>> @@ -41,6 +42,13 @@ static void free_object(struct drm_gem_object *obj)
>>   static void on_frame_done(struct platform_device *pdev,
>>   		int conn_idx, uint64_t fb_cookie)
>>   {
>> +	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
>> +
>> +	if (unlikely(conn_idx >= drm_info->cfg->num_connectors))
>> +		return;
>> +
>> +	xen_drm_front_kms_on_frame_done(&drm_info->pipeline[conn_idx],
>> +			fb_cookie);
>>   }
>>   
>>   static void lastclose(struct drm_device *dev)
>> @@ -157,6 +165,12 @@ int xen_drm_front_drv_probe(struct platform_device *pdev,
>>   		return ret;
>>   	}
>>   
>> +	ret = xen_drm_front_kms_init(drm_info);
>> +	if (ret) {
>> +		DRM_ERROR("Failed to initialize DRM/KMS, ret %d\n", ret);
>> +		goto fail_modeset;
>> +	}
>> +
>>   	dev->irq_enabled = 1;
>>   
>>   	ret = drm_dev_register(dev, 0);
>> @@ -172,6 +186,7 @@ int xen_drm_front_drv_probe(struct platform_device *pdev,
>>   
>>   fail_register:
>>   	drm_dev_unregister(dev);
>> +fail_modeset:
>>   	drm_mode_config_cleanup(dev);
>>   	return ret;
>>   }
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_drv.h b/drivers/gpu/drm/xen/xen_drm_front_drv.h
>> index aaa476535c13..563318b19f34 100644
>> --- a/drivers/gpu/drm/xen/xen_drm_front_drv.h
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_drv.h
>> @@ -20,14 +20,24 @@
>>   #define __XEN_DRM_FRONT_DRV_H_
>>   
>>   #include <drm/drmP.h>
>> +#include <drm/drm_simple_kms_helper.h>
>>   
>>   #include "xen_drm_front.h"
>>   #include "xen_drm_front_cfg.h"
>> +#include "xen_drm_front_conn.h"
>>   
>>   struct xen_drm_front_drm_pipeline {
>>   	struct xen_drm_front_drm_info *drm_info;
>>   
>>   	int index;
>> +
>> +	struct drm_simple_display_pipe pipe;
>> +
>> +	struct drm_connector conn;
>> +	/* these are only for connector mode checking */
>> +	int width, height;
>> +	/* last backend error seen on page flip */
>> +	int pgflip_last_error;
>>   };
>>   
>>   struct xen_drm_front_drm_info {
>> @@ -35,6 +45,8 @@ struct xen_drm_front_drm_info {
>>   	struct xen_drm_front_ops *front_ops;
>>   	struct drm_device *drm_dev;
>>   	struct xen_drm_front_cfg *cfg;
>> +
>> +	struct xen_drm_front_drm_pipeline pipeline[XEN_DRM_FRONT_MAX_CRTCS];
>>   };
>>   
>>   static inline uint64_t xen_drm_front_fb_to_cookie(
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c
>> new file mode 100644
>> index 000000000000..ad94c28835cd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c
>> @@ -0,0 +1,299 @@
>> +/*
>> + *  Xen para-virtual DRM device
>> + *
>> + *   This program is free software; you can redistribute it and/or modify
>> + *   it under the terms of the GNU General Public License as published by
>> + *   the Free Software Foundation; either version 2 of the License, or
>> + *   (at your option) any later version.
>> + *
>> + *   This program is distributed in the hope that it will be useful,
>> + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *   GNU General Public License for more details.
>> + *
>> + * Copyright (C) 2016-2018 EPAM Systems Inc.
>> + *
>> + * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
>> + */
>> +
>> +#include "xen_drm_front_kms.h"
>> +
>> +#include <drm/drmP.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_gem.h>
>> +#include <drm/drm_gem_framebuffer_helper.h>
>> +
>> +#include "xen_drm_front.h"
>> +#include "xen_drm_front_conn.h"
>> +#include "xen_drm_front_drv.h"
>> +
>> +static struct xen_drm_front_drm_pipeline *
>> +to_xen_drm_pipeline(struct drm_simple_display_pipe *pipe)
>> +{
>> +	return container_of(pipe, struct xen_drm_front_drm_pipeline, pipe);
>> +}
>> +
>> +static void fb_destroy(struct drm_framebuffer *fb)
>> +{
>> +	struct xen_drm_front_drm_info *drm_info = fb->dev->dev_private;
>> +
>> +	drm_info->front_ops->fb_detach(drm_info->front_info,
>> +			xen_drm_front_fb_to_cookie(fb));
>> +	drm_gem_fb_destroy(fb);
>> +}
>> +
>> +static struct drm_framebuffer_funcs fb_funcs = {
>> +	.destroy = fb_destroy,
>> +};
>> +
>> +static struct drm_framebuffer *fb_create(struct drm_device *dev,
>> +		struct drm_file *filp, const struct drm_mode_fb_cmd2 *mode_cmd)
>> +{
>> +	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
>> +	static struct drm_framebuffer *fb;
>> +	struct drm_gem_object *gem_obj;
>> +	int ret;
>> +
>> +	fb = drm_gem_fb_create_with_funcs(dev, filp, mode_cmd, &fb_funcs);
>> +	if (IS_ERR_OR_NULL(fb))
>> +		return fb;
>> +
>> +	gem_obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
>> +	if (!gem_obj) {
>> +		DRM_ERROR("Failed to lookup GEM object\n");
>> +		ret = -ENOENT;
>> +		goto fail;
>> +	}
>> +
>> +	drm_gem_object_unreference_unlocked(gem_obj);
>> +
>> +	ret = drm_info->front_ops->fb_attach(
>> +			drm_info->front_info,
>> +			xen_drm_front_dbuf_to_cookie(gem_obj),
>> +			xen_drm_front_fb_to_cookie(fb),
>> +			fb->width, fb->height, fb->format->format);
>> +	if (ret < 0) {
>> +		DRM_ERROR("Back failed to attach FB %p: %d\n", fb, ret);
>> +		goto fail;
>> +	}
>> +
>> +	return fb;
>> +
>> +fail:
>> +	drm_gem_fb_destroy(fb);
>> +	return ERR_PTR(ret);
>> +}
>> +
>> +static const struct drm_mode_config_funcs mode_config_funcs = {
>> +	.fb_create = fb_create,
>> +	.atomic_check = drm_atomic_helper_check,
>> +	.atomic_commit = drm_atomic_helper_commit,
>> +};
>> +
>> +static int display_set_config(struct drm_simple_display_pipe *pipe,
>> +	struct drm_framebuffer *fb)
>> +{
>> +	struct xen_drm_front_drm_pipeline *pipeline =
>> +			to_xen_drm_pipeline(pipe);
>> +	struct drm_crtc *crtc = &pipe->crtc;
>> +	struct xen_drm_front_drm_info *drm_info = pipeline->drm_info;
>> +	int ret;
>> +
>> +	if (fb)
>> +		ret = drm_info->front_ops->mode_set(pipeline,
>> +				crtc->x, crtc->y,
>> +				fb->width, fb->height, fb->format->cpp[0] * 8,
>> +				xen_drm_front_fb_to_cookie(fb));
>> +	else
>> +		ret = drm_info->front_ops->mode_set(pipeline,
>> +				0, 0, 0, 0, 0,
>> +				xen_drm_front_fb_to_cookie(NULL));
> This is a bit much layering, the if (fb) case corresponds to the
> display_enable/disable hooks, pls fold that in instead of the indirection.
> simple helpers guarantee that when the display is on, then you have an fb.
1. Ok, the only reason for having this function was to keep
front_ops->mode_set calls at one place (will be refactored
to be a direct call, not via front_ops).
2. The if (fb) check was meant not to check if simple helpers
may give us some wrong value when we do not expect: there is
nothing wrong with them. The check was for 2 cases when this
function was called: with fb != NULL on display enable and
with fb == NULL on display disable, e.g. fb was used as a
flag in this check.
3. I will remove this function at all and will make direct calls
to the backend on .display_{enable|disable}
>
> Maybe we need to fix the docs, pls check and if that's not clear, submit a
> kernel-doc patch for the simple pipe helpers.
no, nothing wrong here, just see my reasoning above
>> +
>> +	if (ret)
>> +		DRM_ERROR("Failed to set mode to back: %d\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static void display_enable(struct drm_simple_display_pipe *pipe,
>> +		struct drm_crtc_state *crtc_state)
>> +{
>> +	struct drm_crtc *crtc = &pipe->crtc;
>> +	struct drm_framebuffer *fb = pipe->plane.state->fb;
>> +
>> +	if (display_set_config(pipe, fb) == 0)
>> +		drm_crtc_vblank_on(crtc);
> I get the impression your driver doesn't support vblanks (the page flip
> code at least looks like it's only generating a single event),
yes, this is true
>   you also
> don't have a enable/disable_vblank implementation.
this is because with my previous patches [1] these are now handled
by simple helpers, so no need to provide dummy ones in the driver
>   If there's no vblank
> handling then this shouldn't be needed.
yes, I will rework the code, please see below
>> +	else
>> +		DRM_ERROR("Failed to enable display\n");
>> +}
>> +
>> +static void display_disable(struct drm_simple_display_pipe *pipe)
>> +{
>> +	struct drm_crtc *crtc = &pipe->crtc;
>> +
>> +	display_set_config(pipe, NULL);
>> +	drm_crtc_vblank_off(crtc);
>> +	/* final check for stalled events */
>> +	if (crtc->state->event && !crtc->state->active) {
>> +		unsigned long flags;
>> +
>> +		spin_lock_irqsave(&crtc->dev->event_lock, flags);
>> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
>> +		crtc->state->event = NULL;
>> +	}
>> +}
>> +
>> +void xen_drm_front_kms_on_frame_done(
>> +		struct xen_drm_front_drm_pipeline *pipeline,
>> +		uint64_t fb_cookie)
>> +{
>> +	drm_crtc_handle_vblank(&pipeline->pipe.crtc);
> Hm, again this doesn't look like real vblank, but only a page-flip done
> event. If that's correct then please don't use the vblank machinery, but
> just store the event internally (protected with your own private spinlock)
Why can't I use &dev->event_lock? Anyways for handling
page-flip events I will need to lock on it, so I can do
drm_crtc_send_vblank_event?
> and send it out using drm_crtc_send_vblank_event directly. No calls to
> arm_vblank_event or any of the other vblank infrastructure should be
> needed.
will re-work, e.g. will store drm_pending_vblank_event
on .display_update and send out on page flip event from the
backend
> Also please remove the drm_vblank_init() call, since your hw doesn't
> really have vblanks. And exposing vblanks to userspace without
> implementing them is confusing.
will remove all vblank handling at all with the re-work above
>
>> +}
>> +
>> +static void display_send_page_flip(struct drm_simple_display_pipe *pipe,
>> +		struct drm_plane_state *old_plane_state)
>> +{
>> +	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(
>> +			old_plane_state->state, &pipe->plane);
>> +
>> +	/*
>> +	 * If old_plane_state->fb is NULL and plane_state->fb is not,
>> +	 * then this is an atomic commit which will enable display.
>> +	 * If old_plane_state->fb is not NULL and plane_state->fb is,
>> +	 * then this is an atomic commit which will disable display.
>> +	 * Ignore these and do not send page flip as this framebuffer will be
>> +	 * sent to the backend as a part of display_set_config call.
>> +	 */
>> +	if (old_plane_state->fb && plane_state->fb) {
>> +		struct xen_drm_front_drm_pipeline *pipeline =
>> +				to_xen_drm_pipeline(pipe);
>> +		struct xen_drm_front_drm_info *drm_info = pipeline->drm_info;
>> +		int ret;
>> +
>> +		ret = drm_info->front_ops->page_flip(drm_info->front_info,
>> +				pipeline->index,
>> +				xen_drm_front_fb_to_cookie(plane_state->fb));
>> +		pipeline->pgflip_last_error = ret;
>> +		if (ret) {
>> +			DRM_ERROR("Failed to send page flip request to backend: %d\n", ret);
>> +			/*
>> +			 * As we are at commit stage the DRM core will anyways
>> +			 * wait for the vblank and knows nothing about our
>> +			 * failure. The best we can do is to handle
>> +			 * vblank now, so there is no vblank/flip_done
>> +			 * time outs
>> +			 */
>> +			drm_crtc_handle_vblank(&pipeline->pipe.crtc);
>> +		}
>> +	}
>> +}
>> +
>> +static int display_prepare_fb(struct drm_simple_display_pipe *pipe,
>> +		struct drm_plane_state *plane_state)
>> +{
>> +	struct xen_drm_front_drm_pipeline *pipeline =
>> +			to_xen_drm_pipeline(pipe);
>> +
>> +	if (pipeline->pgflip_last_error) {
>> +		int ret;
>> +
>> +		/* if previous page flip didn't succeed then report the error */
>> +		ret = pipeline->pgflip_last_error;
>> +		/* and let us try to page flip next time */
>> +		pipeline->pgflip_last_error = 0;
>> +		return ret;
>> +	}
> Nope, this isn't how the uapi works. If your flips fail then we might need
> to add some error status thing to the drm events, but you can't make the
> next flip fail.
Well, yes, there is no way for me to tell that the page flip
has failed, so this is why I tried to do this workaround with
the next page-flip. The reason for that is that if, for example,
we are disconnected from the backend for some reason, there is
no way for me to tell the user-space that hey, please, do not
send any other page flips. If backend can recover and that was
a one time error then yes, the code I have will do wrong thing
(fail the current page flip), but if the error state is persistent
then I will be able to tell the user-space to stop by returning errors.
This is kind of trade-off which I am not sure how to solve correctly.

Do you think I can remove this workaround completely?
> -Daniel
>
>> +	return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
>> +}
>> +
>> +static void display_update(struct drm_simple_display_pipe *pipe,
>> +		struct drm_plane_state *old_plane_state)
>> +{
>> +	struct drm_crtc *crtc = &pipe->crtc;
>> +	struct drm_pending_vblank_event *event;
>> +
>> +	event = crtc->state->event;
>> +	if (event) {
>> +		struct drm_device *dev = crtc->dev;
>> +		unsigned long flags;
>> +
>> +		crtc->state->event = NULL;
>> +
>> +		spin_lock_irqsave(&dev->event_lock, flags);
>> +		if (drm_crtc_vblank_get(crtc) == 0)
>> +			drm_crtc_arm_vblank_event(crtc, event);
>> +		else
>> +			drm_crtc_send_vblank_event(crtc, event);
>> +		spin_unlock_irqrestore(&dev->event_lock, flags);
>> +	}
>> +	/*
>> +	 * Send page flip request to the backend *after* we have event armed/
>> +	 * sent above, so on page flip done event from the backend we can
>> +	 * deliver it while handling vblank.
>> +	 */
>> +	display_send_page_flip(pipe, old_plane_state);
>> +}
>> +
>> +static const struct drm_simple_display_pipe_funcs display_funcs = {
>> +	.enable = display_enable,
>> +	.disable = display_disable,
>> +	.prepare_fb = display_prepare_fb,
>> +	.update = display_update,
>> +};
>> +
>> +static int display_pipe_init(struct xen_drm_front_drm_info *drm_info,
>> +		int index, struct xen_drm_front_cfg_connector *cfg,
>> +		struct xen_drm_front_drm_pipeline *pipeline)
>> +{
>> +	struct drm_device *dev = drm_info->drm_dev;
>> +	const uint32_t *formats;
>> +	int format_count;
>> +	int ret;
>> +
>> +	pipeline->drm_info = drm_info;
>> +	pipeline->index = index;
>> +	pipeline->height = cfg->height;
>> +	pipeline->width = cfg->width;
>> +
>> +	ret = xen_drm_front_conn_init(drm_info, &pipeline->conn);
>> +	if (ret)
>> +		return ret;
>> +
>> +	formats = xen_drm_front_conn_get_formats(&format_count);
>> +
>> +	return drm_simple_display_pipe_init(dev, &pipeline->pipe,
>> +			&display_funcs, formats, format_count,
>> +			NULL, &pipeline->conn);
>> +}
>> +
>> +int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info)
>> +{
>> +	struct drm_device *dev = drm_info->drm_dev;
>> +	int i, ret;
>> +
>> +	drm_mode_config_init(dev);
>> +
>> +	dev->mode_config.min_width = 0;
>> +	dev->mode_config.min_height = 0;
>> +	dev->mode_config.max_width = 4095;
>> +	dev->mode_config.max_height = 2047;
>> +	dev->mode_config.funcs = &mode_config_funcs;
>> +
>> +	for (i = 0; i < drm_info->cfg->num_connectors; i++) {
>> +		struct xen_drm_front_cfg_connector *cfg =
>> +				&drm_info->cfg->connectors[i];
>> +		struct xen_drm_front_drm_pipeline *pipeline =
>> +				&drm_info->pipeline[i];
>> +
>> +		ret = display_pipe_init(drm_info, i, cfg, pipeline);
>> +		if (ret) {
>> +			drm_mode_config_cleanup(dev);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	drm_mode_config_reset(dev);
>> +	return 0;
>> +}
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.h b/drivers/gpu/drm/xen/xen_drm_front_kms.h
>> new file mode 100644
>> index 000000000000..65a50033bb9b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.h
>> @@ -0,0 +1,30 @@
>> +/*
>> + *  Xen para-virtual DRM device
>> + *
>> + *   This program is free software; you can redistribute it and/or modify
>> + *   it under the terms of the GNU General Public License as published by
>> + *   the Free Software Foundation; either version 2 of the License, or
>> + *   (at your option) any later version.
>> + *
>> + *   This program is distributed in the hope that it will be useful,
>> + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + *   GNU General Public License for more details.
>> + *
>> + * Copyright (C) 2016-2018 EPAM Systems Inc.
>> + *
>> + * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@...m.com>
>> + */
>> +
>> +#ifndef __XEN_DRM_FRONT_KMS_H_
>> +#define __XEN_DRM_FRONT_KMS_H_
>> +
>> +#include "xen_drm_front_drv.h"
>> +
>> +int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info);
>> +
>> +void xen_drm_front_kms_on_frame_done(
>> +		struct xen_drm_front_drm_pipeline *pipeline,
>> +		uint64_t fb_cookie);
>> +
>> +#endif /* __XEN_DRM_FRONT_KMS_H_ */
>> -- 
>> 2.7.4
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@...ts.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
[1] https://patchwork.kernel.org/patch/10211997/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ