Skip to contentSkip to conversation

drm/xen-front: Add support for Xen PV display frontend

PATCH Superseded Oleksandr Andrushchenko 9 participants 109 messages Feb 21, 2018 – Mar 6, 2018 Page 1 of 2

Subsystems (3)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover drm/xen-front: Add support for Xen PV display frontend

From: Oleksandr Andrushchenko <[email protected]>

Hello!

This patch series adds support for Xen [1] para-virtualized frontend display driver. It implements the protocol from include/xen/interface/io/displif.h [2].
Accompanying backend [3] is implemented as a user-space application and its helper library [4], capable of running as a Weston client or DRM master.
Configuration of both backend and frontend is done via Xen guest domain configuration options [5].

*******************************************************************************
* Driver limitations
*******************************************************************************
1. Configuration options 1.1 (contiguous display buffers) and 2 (backend allocated buffers) below are not supported at the same time.

2. Only primary plane without additional properties is supported.

3. Only one video mode supported which resolution is configured via XenStore.

4. All CRTCs operate at fixed frequency of 60Hz.

*******************************************************************************
* Driver modes of operation in terms of display buffers used
*******************************************************************************
Depending on the requirements for the para-virtualized environment, namely requirements dictated by the accompanying DRM/(v)GPU drivers running in both host and guest environments, number of operating modes of para-virtualized display driver are supported:
- display buffers can be allocated by either frontend driver or backend
- display buffers can be allocated to be contiguous in memory or not

Note! Frontend driver itself has no dependency on contiguous memory for
its operation.

*******************************************************************************
* 1. Buffers allocated by the frontend driver.
*******************************************************************************

The below modes of operation are configured at compile-time via frontend driver's kernel configuration.

1.1. Front driver configured to use GEM CMA helpers
This use-case is useful when used with accompanying DRM/vGPU driver in guest domain which was designed to only work with contiguous buffers, e.g. DRM driver based on GEM CMA helpers: such drivers can only import contiguous PRIME buffers, thus requiring frontend driver to provide such. In order to implement this mode of operation para-virtualized frontend driver can be configured to use GEM CMA helpers.

1.2. Front driver doesn't use GEM CMA
If accompanying drivers can cope with non-contiguous memory then, to lower pressure on CMA subsystem of the kernel, driver can allocate buffers from system memory.

Note! If used with accompanying DRM/(v)GPU drivers this mode of operation
may require IOMMU support on the platform, so accompanying DRM/vGPU hardware can still reach display buffer memory while importing PRIME buffers from the frontend driver.

*******************************************************************************
* 2. Buffers allocated by the backend
*******************************************************************************

This mode of operation is run-time configured via guest domain configuration through XenStore entries.

For systems which do not provide IOMMU support, but having specific requirements for display buffers it is possible to allocate such buffers at backend side and share those with the frontend.
For example, if host domain is 1:1 mapped and has DRM/GPU hardware expecting physically contiguous memory, this allows implementing zero-copying use-cases.

I would like to thank at least, but not at last the following people/communities who helped this driver to happen ;)

1. My team at EPAM for continuous support
2. Xen community for answering tons of questions on different modes of operation of the driver with respect to virtualized environment.
3. Rob Clark for "GEM allocation for para-virtualized DRM driver" [6]
4. Maarten Lankhorst for "Atomic driver and old remove FB behavior" [7]
5. Ville Syrjälä for "Questions on page flips and atomic modeset" [8]

Thank you,
Oleksandr Andrushchenko

P.S. There are two dependencies for this driver limiting some of the use-cases which are on review now:
1. "drm/simple_kms_helper: Add {enable|disable}_vblank callback support" [9]
2. "drm/simple_kms_helper: Fix NULL pointer dereference with no active CRTC" [10]

[1] https://wiki.xen.org/wiki/Paravirtualization_(PV)#PV_IO_Drivers
[2] https://elixir.bootlin.com/linux/v4.16-rc2/source/include/xen/interface/io/displif.h
[3] https://github.com/xen-troops/displ_be
[4] https://github.com/xen-troops/libxenbe
[5] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/man/xl.cfg.pod.5.in;h=a699367779e2ae1212ff8f638eff0206ec1a1cc9;hb=refs/heads/master#l1257
[6] https://lists.freedesktop.org/archives/dri-devel/2017-March/136038.html
[7] https://www.spinics.net/lists/dri-devel/msg164102.html
[8] https://www.spinics.net/lists/dri-devel/msg164463.html
[9] https://patchwork.freedesktop.org/series/38073/
[10] https://patchwork.freedesktop.org/series/38139/

Oleksandr Andrushchenko (9):
drm/xen-front: Introduce Xen para-virtualized frontend driver drm/xen-front: Implement Xen bus state handling drm/xen-front: Read driver configuration from Xen store drm/xen-front: Implement Xen event channel handling drm/xen-front: Implement handling of shared display buffers drm/xen-front: Introduce DRM/KMS virtual display driver drm/xen-front: Implement KMS/connector handling drm/xen-front: Implement GEM operations drm/xen-front: Implement communication with backend

 drivers/gpu/drm/Kconfig                     |   2 +
 drivers/gpu/drm/Makefile                    |   1 +
 drivers/gpu/drm/xen/Kconfig                 |  30 ++
 drivers/gpu/drm/xen/Makefile                |  17 +
 drivers/gpu/drm/xen/xen_drm_front.c         | 712 ++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front.h         | 154 ++++++
 drivers/gpu/drm/xen/xen_drm_front_cfg.c     |  84 ++++
 drivers/gpu/drm/xen/xen_drm_front_cfg.h     |  45 ++
 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     | 294 ++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.h     |  73 +++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c | 399 ++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h |  89 ++++
 drivers/gpu/drm/xen/xen_drm_front_gem.c     | 360 ++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_gem.h     |  46 ++
 drivers/gpu/drm/xen/xen_drm_front_gem_cma.c |  93 ++++
 drivers/gpu/drm/xen/xen_drm_front_kms.c     | 299 ++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_kms.h     |  30 ++
 drivers/gpu/drm/xen/xen_drm_front_shbuf.c   | 430 +++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_shbuf.h   |  80 ++++
 21 files changed, 3398 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/Kconfig
 create mode 100644 drivers/gpu/drm/xen/Makefile
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.h
 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_drv.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem_cma.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.h
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#1 lore raw

PATCH 1/9 drm/xen-front: Introduce Xen para-virtualized frontend driver

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
 drivers/gpu/drm/Kconfig             |  2 +
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
 drivers/gpu/drm/xen/Makefile        |  5 +++
 drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/Kconfig
 create mode 100644 drivers/gpu/drm/xen/Makefile
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c
drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
 source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
 obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
 obj-$(CONFIG_DRM_PL111) += pl111/
 obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +83 -0

83 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#2 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
 drivers/gpu/drm/Kconfig             |  2 +
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
 drivers/gpu/drm/xen/Makefile        |  5 +++
 drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/Kconfig
 create mode 100644 drivers/gpu/drm/xen/Makefile
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c
drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
 source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
 obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
 obj-$(CONFIG_DRM_PL111) += pl111/
 obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Use SPDX identifier instead (same applies for all other new sources):

// SPDX-License-Identifier: GPL-2.0

Quoted 41 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +41 -0
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+		enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+		const struct xenbus_device_id *id)
+{
+	return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+	return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+	{ XENDISPL_DRIVER_NAME },
+	{ "" }
+};
+
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,
+};

drivers/gpu/drm/xen/xen_drm_front.c line 63

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+
+static int __init xen_drv_init(void)
+{
+	if (!xen_domain())
+		return -ENODEV;
+
+	if (xen_initial_domain()) {
+		DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial domain\n");
+		return -ENODEV;
+	}

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

Juergen

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#3 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 96 lines · Juergen Gross
Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
  drivers/gpu/drm/Kconfig             |  2 +
  drivers/gpu/drm/Makefile            |  1 +
  drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
  drivers/gpu/drm/xen/Makefile        |  5 +++
  drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
  5 files changed, 108 insertions(+)

create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
  source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
  # Keep legacy drivers last
 
  menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
  obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
  obj-$(CONFIG_DRM_PL111) += pl111/
  obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Use SPDX identifier instead (same applies for all other new sources):

Quoted 1 line

// SPDX-License-Identifier: GPL-2.0

Will update, thank you

Quoted 45 lines
Quoted 45 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +45 -0
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+		enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+		const struct xenbus_device_id *id)
+{
+	return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+	return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+	{ XENDISPL_DRIVER_NAME },
+	{ "" }
+};
+
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+	if (!xen_domain())
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front.c line 63

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +6 -0
+		return -ENODEV;
+
+	if (xen_initial_domain()) {
+		DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial domain\n");
+		return -ENODEV;
+	}

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

It is possible (and in my use-case backend indeed runs in a driver domain). I was just not sure if it is really a good idea to allow that. If you think this is ok, then I'll remove this check

Quoted 2 lines

Juergen

Thank you,
Oleksandr
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#4 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 155 lines · Oleksandr Andrushchenko
Quoted 98 lines · Juergen Gross
Quoted 86 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

Signed-off-by: Oleksandr Andrushchenko <[email protected]>
---
  drivers/gpu/drm/Kconfig             |  2 + drivers/gpu/drm/Makefile            |  1 + drivers/gpu/drm/xen/Kconfig         | 17 ++++++++ drivers/gpu/drm/xen/Makefile        |  5 +++ drivers/gpu/drm/xen/xen_drm_front.c | 83
+++++++++++++++++++++++++++++++++++++

  5 files changed, 108 insertions(+)

  create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +0 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"

    source "drivers/gpu/drm/tve200/Kconfig"
  +source "drivers/gpu/drm/xen/Kconfig"
+
  # Keep legacy drivers last
    menuconfig DRM_LEGACY

drivers/gpu/drm/Makefile +0 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)    += mxsfb/

  obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
  obj-$(CONFIG_DRM_PL111) += pl111/
  obj-$(CONFIG_DRM_TVE200) += tve200/

drivers/gpu/drm/Makefile +1 -0
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+    bool "DRM Support for Xen guest OS"
+    depends on XEN
+    help
+      Choose this option if you want to enable DRM support
+      for Xen.
+
+config DRM_XEN_FRONTEND
+    tristate "Para-virtualized frontend driver for Xen guest OS"
+    depends on DRM_XEN
+    depends on DRM
+    select DRM_KMS_HELPER
+    select VIDEOMODE_HELPERS
+    select XEN_XENBUS_FRONTEND
+    help
+      Choose this option if you want to enable a para-virtualized
+      frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +4 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  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

Quoted 8 lines

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.

Use SPDX identifier instead (same applies for all other new sources):

Quoted 1 line

// SPDX-License-Identifier: GPL-2.0

Will update, thank you

Quoted 46 lines
Quoted 46 lines

+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */

drivers/gpu/drm/xen/xen_drm_front.c new file +41 -0
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+        enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+        const struct xenbus_device_id *id)
+{
+    return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+    return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+    { XENDISPL_DRIVER_NAME },
+    { "" }
+};
+
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+    if (!xen_domain())
+        return -ENODEV;
Quoted 8 lines
Quoted 6 lines

+
+    if (xen_initial_domain()) {
+        DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial domain\n");
+        return -ENODEV;
+    }

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

Quoted 4 lines

It is possible (and in my use-case backend indeed runs in a driver domain). I was just not sure if it is really a good idea to allow that. If you think this is ok, then I'll remove this check

I don't think the driver should decide that. This would be the job of Xen tools IMO.

Juergen

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#5 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 156 lines · Juergen Gross
Quoted 155 lines · Oleksandr Andrushchenko
Quoted 98 lines · Juergen Gross
Quoted 86 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

Signed-off-by: Oleksandr Andrushchenko
<[email protected]>

---
   drivers/gpu/drm/Kconfig             |  2 +
   drivers/gpu/drm/Makefile            |  1 +
   drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
   drivers/gpu/drm/xen/Makefile        |  5 +++
   drivers/gpu/drm/xen/xen_drm_front.c | 83
+++++++++++++++++++++++++++++++++++++
   5 files changed, 108 insertions(+)

  create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +1 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
     source "drivers/gpu/drm/tve200/Kconfig"
   +source "drivers/gpu/drm/xen/Kconfig"
+
   # Keep legacy drivers last
     menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)    += mxsfb/
   obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
   obj-$(CONFIG_DRM_PL111) += pl111/
   obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+    bool "DRM Support for Xen guest OS"
+    depends on XEN
+    help
+      Choose this option if you want to enable DRM support
+      for Xen.
+
+config DRM_XEN_FRONTEND
+    tristate "Para-virtualized frontend driver for Xen guest OS"
+    depends on DRM_XEN
+    depends on DRM
+    select DRM_KMS_HELPER
+    select VIDEOMODE_HELPERS
+    select XEN_XENBUS_FRONTEND
+    help
+      Choose this option if you want to enable a para-virtualized
+      frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +4 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  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

Quoted 8 lines

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.

Use SPDX identifier instead (same applies for all other new sources):

Quoted 1 line

// SPDX-License-Identifier: GPL-2.0

Will update, thank you

Quoted 54 lines
Quoted 49 lines

+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */

drivers/gpu/drm/xen/xen_drm_front.c new file +44 -0
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+        enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+        const struct xenbus_device_id *id)
+{
+    return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+    return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+    { XENDISPL_DRIVER_NAME },
+    { "" }
+};
+
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+    if (!xen_domain())
+        return -ENODEV;
+
+    if (xen_initial_domain()) {
+        DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial
Quoted 3 lines

domain\n");
+        return -ENODEV;
+    }

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

Quoted 6 lines
Quoted 4 lines

It is possible (and in my use-case backend indeed runs in a driver domain). I was just not sure if it is really a good idea to allow that. If you think this is ok, then I'll remove this check

I don't think the driver should decide that. This would be the job of Xen tools IMO.

Agree, will remove

Quoted 2 lines

Juergen

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#6 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Juergen Gross
Quoted 156 lines · Juergen Gross
Quoted 155 lines · Oleksandr Andrushchenko
Quoted 98 lines · Juergen Gross
Quoted 86 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

Signed-off-by: Oleksandr Andrushchenko
<[email protected]>

---
   drivers/gpu/drm/Kconfig             |  2 +
   drivers/gpu/drm/Makefile            |  1 +
   drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
   drivers/gpu/drm/xen/Makefile        |  5 +++
   drivers/gpu/drm/xen/xen_drm_front.c | 83
+++++++++++++++++++++++++++++++++++++
   5 files changed, 108 insertions(+)

  create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +1 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
     source "drivers/gpu/drm/tve200/Kconfig"
   +source "drivers/gpu/drm/xen/Kconfig"
+
   # Keep legacy drivers last
     menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)    += mxsfb/
   obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
   obj-$(CONFIG_DRM_PL111) += pl111/
   obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+    bool "DRM Support for Xen guest OS"
+    depends on XEN
+    help
+      Choose this option if you want to enable DRM support
+      for Xen.
+
+config DRM_XEN_FRONTEND
+    tristate "Para-virtualized frontend driver for Xen guest OS"
+    depends on DRM_XEN
+    depends on DRM
+    select DRM_KMS_HELPER
+    select VIDEOMODE_HELPERS
+    select XEN_XENBUS_FRONTEND
+    help
+      Choose this option if you want to enable a para-virtualized
+      frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +4 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  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

Quoted 8 lines

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.

Use SPDX identifier instead (same applies for all other new sources):

Quoted 1 line

// SPDX-License-Identifier: GPL-2.0

Will update, thank you

Quoted 54 lines
Quoted 49 lines

+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */

drivers/gpu/drm/xen/xen_drm_front.c new file +44 -0
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+        enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+        const struct xenbus_device_id *id)
+{
+    return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+    return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+    { XENDISPL_DRIVER_NAME },
+    { "" }
+};
+
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+    if (!xen_domain())
+        return -ENODEV;
+
+    if (xen_initial_domain()) {
+        DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial
Quoted 3 lines

domain\n");
+        return -ENODEV;
+    }

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

Quoted 6 lines
Quoted 4 lines

It is possible (and in my use-case backend indeed runs in a driver domain). I was just not sure if it is really a good idea to allow that. If you think this is ok, then I'll remove this check

I don't think the driver should decide that. This would be the job of Xen tools IMO.

Agree, will remove

Quoted 2 lines

Juergen

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#7 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Juergen Gross
Quoted 96 lines · Juergen Gross
Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
  drivers/gpu/drm/Kconfig             |  2 +
  drivers/gpu/drm/Makefile            |  1 +
  drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
  drivers/gpu/drm/xen/Makefile        |  5 +++
  drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
  5 files changed, 108 insertions(+)

create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
  source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
  # Keep legacy drivers last
 
  menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
  obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
  obj-$(CONFIG_DRM_PL111) += pl111/
  obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Use SPDX identifier instead (same applies for all other new sources):

Quoted 1 line

// SPDX-License-Identifier: GPL-2.0

Will update, thank you

Quoted 45 lines
Quoted 45 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +45 -0
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <[email protected]>
+ */
+
+#include <drm/drmP.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/displif.h>
+
+static void backend_on_changed(struct xenbus_device *xb_dev,
+		enum xenbus_state backend_state)
+{
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+		const struct xenbus_device_id *id)
+{
+	return 0;
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+	return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+	{ XENDISPL_DRIVER_NAME },
+	{ "" }
+};
+
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+	if (!xen_domain())
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front.c line 63

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +6 -0
+		return -ENODEV;
+
+	if (xen_initial_domain()) {
+		DRM_ERROR(XENDISPL_DRIVER_NAME " cannot run in initial domain\n");
+		return -ENODEV;
+	}

Why not? Wouldn't that be possible in case of the backend living in a driver domain?

It is possible (and in my use-case backend indeed runs in a driver domain). I was just not sure if it is really a good idea to allow that. If you think this is ok, then I'll remove this check

Quoted 2 lines

Juergen

Thank you,
Oleksandr

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#8 lore raw

Re: [Xen-devel] [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Oleksandr Andrushchenko
Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
 drivers/gpu/drm/Kconfig             |  2 +
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
 drivers/gpu/drm/xen/Makefile        |  5 +++
 drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/Kconfig
 create mode 100644 drivers/gpu/drm/xen/Makefile
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c
drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
 source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
 obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
 obj-$(CONFIG_DRM_PL111) += pl111/
 obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

Thanks, Roger.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#9 lore raw

Re: [Xen-devel] [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 120 lines · Roger Pau Monné
Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
  drivers/gpu/drm/Kconfig             |  2 +
  drivers/gpu/drm/Makefile            |  1 +
  drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
  drivers/gpu/drm/xen/Makefile        |  5 +++
  drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
  5 files changed, 108 insertions(+)

create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
  source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
  # Keep legacy drivers last
 
  menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
  obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
  obj-$(CONFIG_DRM_PL111) += pl111/
  obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

Quoted 2 lines

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

I am in any way expert in licensing, but the above seems to be /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
At least this is what I see at [1] for MIT.
Could you please tell which license(s) as listed at [1] would be appropriate for Xen drivers in terms of how it is expected to appear in the kernel code, e.g. expected SPDX-License-Identifier?

Quoted 1 line

Thanks, Roger.

Thank you,
Oleksandr

[1] https://spdx.org/licenses/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#10 lore raw

Re: [Xen-devel] [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 46 lines · Oleksandr Andrushchenko
Quoted 43 lines · Roger Pau Monné
Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

Quoted 2 lines

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

Quoted 7 lines

I am in any way expert in licensing, but the above seems to be /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
At least this is what I see at [1] for MIT.
Could you please tell which license(s) as listed at [1] would be appropriate for Xen drivers in terms of how it is expected to appear in the kernel code, e.g. expected SPDX-License-Identifier?

I would be fine with anything MIT/BSD-*/Apache-* like. In the Xen community we have generally done dual GPL-2.0 MIT, so your proposed tag looks fine IMO (I would also personally be fine with MIT/BSD-*/Apache-* only).

The point is that it would be good to have the code under a more permissive license so it can be integrated into non GPL OSes in the future if needed, and that your code could be used as a reference for that.

Thanks, Roger.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#11 lore raw

Re: [Xen-devel] [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 54 lines · Roger Pau Monné
Quoted 46 lines · Oleksandr Andrushchenko
Quoted 43 lines · Roger Pau Monné
Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

Quoted 2 lines

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

Quoted 7 lines

I am in any way expert in licensing, but the above seems to be /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
At least this is what I see at [1] for MIT.
Could you please tell which license(s) as listed at [1] would be appropriate for Xen drivers in terms of how it is expected to appear in the kernel code, e.g. expected SPDX-License-Identifier?

Quoted 4 lines

I would be fine with anything MIT/BSD-*/Apache-* like. In the Xen community we have generally done dual GPL-2.0 MIT, so your proposed tag looks fine IMO (I would also personally be fine with MIT/BSD-*/Apache-* only).

Ok, then I am about to use /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */

Quoted 5 lines

The point is that it would be good to have the code under a more permissive license so it can be integrated into non GPL OSes in the future if needed, and that your code could be used as a reference for that.

That is clear, no objections

Quoted 1 line

Thanks, Roger.

Thank you,
Oleksandr
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#12 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Roger Pau Monné
Quoted 54 lines · Roger Pau Monné
Quoted 46 lines · Oleksandr Andrushchenko
Quoted 43 lines · Roger Pau Monné
Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

Quoted 2 lines

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

Quoted 7 lines

I am in any way expert in licensing, but the above seems to be /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
At least this is what I see at [1] for MIT.
Could you please tell which license(s) as listed at [1] would be appropriate for Xen drivers in terms of how it is expected to appear in the kernel code, e.g. expected SPDX-License-Identifier?

Quoted 4 lines

I would be fine with anything MIT/BSD-*/Apache-* like. In the Xen community we have generally done dual GPL-2.0 MIT, so your proposed tag looks fine IMO (I would also personally be fine with MIT/BSD-*/Apache-* only).

Ok, then I am about to use /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */

Quoted 5 lines

The point is that it would be good to have the code under a more permissive license so it can be integrated into non GPL OSes in the future if needed, and that your code could be used as a reference for that.

That is clear, no objections

Quoted 1 line

Thanks, Roger.

Thank you,
Oleksandr

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#13 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Roger Pau Monné
Quoted 120 lines · Roger Pau Monné
Quoted 82 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
  drivers/gpu/drm/Kconfig             |  2 +
  drivers/gpu/drm/Makefile            |  1 +
  drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
  drivers/gpu/drm/xen/Makefile        |  5 +++
  drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
  5 files changed, 108 insertions(+)

create mode 100644 drivers/gpu/drm/xen/Kconfig create mode 100644 drivers/gpu/drm/xen/Makefile create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c

drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
  source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
  # Keep legacy drivers last
 
  menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
  obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
  obj-$(CONFIG_DRM_PL111) += pl111/
  obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +2 -0
new file mode 100644
index 000000000000..fd372fb464a1
@@ -0,0 +1,83 @@
+/*
+ *  Xen para-virtual DRM device

drivers/gpu/drm/xen/xen_drm_front.c line 12

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c new file +10 -0
+ *
+ *   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.

Most Xen drivers in Linux use a dual GPL/BSD license, so that they can be imported into other non GPL OSes:

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license:

Permission is hereby granted, free of charge, to any person obtaining a copy of this source file (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 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.

Quoted 2 lines

IMO it would be good to release this driver under the same license, so it can be incorporated into other OSes.

I am in any way expert in licensing, but the above seems to be /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
At least this is what I see at [1] for MIT.
Could you please tell which license(s) as listed at [1] would be appropriate for Xen drivers in terms of how it is expected to appear in the kernel code, e.g. expected SPDX-License-Identifier?

Quoted 1 line

Thanks, Roger.

Thank you,
Oleksandr

[1] https://spdx.org/licenses/

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#14 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Oleksandr Andrushchenko

drivers/gpu/drm/xen/xen_drm_front.c line 52

Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,

What does "_on_" stand for?

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#15 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 7 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front.c line 52

Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,

What does "_on_" stand for?

Well, it is somewhat like a hint that this is called "on" event, e.g. event when the other end state has changed, backend in this case. It could be something like "backend_on_state_changed"

Quoted 1 line

-boris

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#16 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 11 lines · Oleksandr Andrushchenko
Quoted 7 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front.c line 52

Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,

What does "_on_" stand for?

Well, it is somewhat like a hint that this is called "on" event, e.g. event when the other end state has changed, backend in this case. It could be something like "backend_on_state_changed"

If you look at other xenbus_drivers none of the uses this so I think we should stick to conventional naming. (and the same applies to other backend_on_* routines).

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#17 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

Quoted 8 lines · Boris Ostrovsky
Quoted 7 lines · Oleksandr Andrushchenko
Quoted 6 lines · Boris Ostrovsky
Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,
Quoted 7 lines
Quoted 4 lines
Quoted 1 line

What does "_on_" stand for?

Well, it is somewhat like a hint that this is called "on" event, e.g. event when the other end state has changed, backend in this case. It could be something like "backend_on_state_changed"

If you look at other xenbus_drivers none of the uses this so I think we should stick to conventional naming. (and the same applies to other backend_on_* routines).

ok, no problem. will rename to be aligned with other frontends

Quoted 2 lines

-boris

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#18 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Boris Ostrovsky
Quoted 8 lines · Boris Ostrovsky
Quoted 7 lines · Oleksandr Andrushchenko
Quoted 6 lines · Boris Ostrovsky
Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+    .ids = xen_drv_ids,
+    .probe = xen_drv_probe,
+    .remove = xen_drv_remove,
+    .otherend_changed = backend_on_changed,
Quoted 7 lines
Quoted 4 lines
Quoted 1 line

What does "_on_" stand for?

Well, it is somewhat like a hint that this is called "on" event, e.g. event when the other end state has changed, backend in this case. It could be something like "backend_on_state_changed"

If you look at other xenbus_drivers none of the uses this so I think we should stick to conventional naming. (and the same applies to other backend_on_* routines).

ok, no problem. will rename to be aligned with other frontends

Quoted 2 lines

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#19 lore raw

Re: [PATCH 1/9] drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Boris Ostrovsky
Quoted 7 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front.c line 52

Quoted 5 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front.c new file +5 -0
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = backend_on_changed,

What does "_on_" stand for?

Well, it is somewhat like a hint that this is called "on" event, e.g. event when the other end state has changed, backend in this case. It could be something like "backend_on_state_changed"

Quoted 1 line

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#20 lore raw

PATCH 1/9 drm/xen-front: Introduce Xen para-virtualized frontend driver

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Introduce skeleton of the para-virtualized Xen display frontend driver. This patch only adds required essential stubs.

---
 drivers/gpu/drm/Kconfig             |  2 +
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/xen/Kconfig         | 17 ++++++++
 drivers/gpu/drm/xen/Makefile        |  5 +++
 drivers/gpu/drm/xen/xen_drm_front.c | 83 +++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/Kconfig
 create mode 100644 drivers/gpu/drm/xen/Makefile
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.c
drivers/gpu/drm/Kconfig +2 -0
index deeefa7a1773..757825ac60df 100644
@@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
 
 source "drivers/gpu/drm/tve200/Kconfig"
 
+source "drivers/gpu/drm/xen/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
index 50093ff4479b..9d66657ea117 100644
@@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/
 obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
 obj-$(CONFIG_DRM_PL111) += pl111/
 obj-$(CONFIG_DRM_TVE200) += tve200/
+obj-$(CONFIG_DRM_XEN) += xen/
drivers/gpu/drm/xen/Kconfig new file +17 -0
new file mode 100644
index 000000000000..4cca160782ab
@@ -0,0 +1,17 @@
+config DRM_XEN
+	bool "DRM Support for Xen guest OS"
+	depends on XEN
+	help
+	  Choose this option if you want to enable DRM support
+	  for Xen.
+
+config DRM_XEN_FRONTEND
+	tristate "Para-virtualized frontend driver for Xen guest OS"
+	depends on DRM_XEN
+	depends on DRM
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select XEN_XENBUS_FRONTEND
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend DRM/KMS driver for Xen guest OSes.
drivers/gpu/drm/xen/Makefile new file +5 -0
new file mode 100644
index 000000000000..967074d348f6
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_xen_front-objs := xen_drm_front.o
+
+obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c new file +83 -0

83 lines not on this page · raw message

Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#21 lore raw

PATCH 2/9 drm/xen-front: Implement Xen bus state handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to the state diagram and recovery flow from display para-virtualized
protocol: xen/interface/io/displif.h.

---
 drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
drivers/gpu/drm/xen/xen_drm_front.c +123 -1
index fd372fb464a1..d0306f9d660d 100644
@@ -24,19 +24,141 @@
 
 #include <xen/interface/io/displif.h>
 
+#include "xen_drm_front.h"
+
+static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
+{
+}
+
+static int backend_on_initwait(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static int backend_on_connected(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static void backend_on_disconnected(struct xen_drm_front_info *front_info)
+{
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static void backend_on_changed(struct xenbus_device *xb_dev,
 		enum xenbus_state backend_state)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	DRM_DEBUG("Backend state is %s, front is %s\n",
+			xenbus_strstate(backend_state),
+			xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		if (xb_dev->state != XenbusStateInitialising)
+			break;
+
+		ret = backend_on_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = backend_on_connected(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		backend_on_disconnected(front_info);
+		break;
+	}
 }
 
 static int xen_drv_probe(struct xenbus_device *xb_dev,
 		const struct xenbus_device_id *id)
 {
-	return 0;
+	struct xen_drm_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+			sizeof(*front_info), GFP_KERNEL);
+	if (!front_info) {
+		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");
+		return -ENOMEM;
+	}
+
+	front_info->xb_dev = xb_dev;
+	dev_set_drvdata(&xb_dev->dev, front_info);
+	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
 
 static int xen_drv_remove(struct xenbus_device *dev)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev);
+	int to = 100;
+
+	xenbus_switch_state(dev, XenbusStateClosing);
+
+	/*
+	 * On driver removal it is disconnected from XenBus,
+	 * so no backend state change events come via .otherend_changed
+	 * callback. This prevents us from exiting gracefully, e.g.
+	 * signaling the backend to free event channels, waiting for its
+	 * state to change to XenbusStateClosed and cleaning at our end.
+	 * Normally when front driver removed backend will finally go into
+	 * XenbusStateInitWait state.
+	 *
+	 * Workaround: read backend's state manually and wait with time-out.
+	 */
+	while ((xenbus_read_unsigned(front_info->xb_dev->otherend,
+			"state", XenbusStateUnknown) != XenbusStateInitWait) &&
+			to--)
+		msleep(10);
+
+	if (!to)
+		DRM_ERROR("Backend state is %s while removing driver\n",
+			xenbus_strstate(xenbus_read_unsigned(
+					front_info->xb_dev->otherend,
+					"state", XenbusStateUnknown)));
+
+	xen_drv_remove_internal(front_info);
+	xenbus_frontend_closed(dev);
 	return 0;
 }
 
drivers/gpu/drm/xen/xen_drm_front.h new file +26 -0
new file mode 100644
index 000000000000..8af46850f126
@@ -0,0 +1,26 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_H_
+#define __XEN_DRM_FRONT_H_
+
+struct xen_drm_front_info {
+	struct xenbus_device *xb_dev;
+};
+
+#endif /* __XEN_DRM_FRONT_H_ */
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#22 lore raw

Re: [PATCH 2/9] drm/xen-front: Implement Xen bus state handling

Quoted 109 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to the state diagram and recovery flow from display para-virtualized
protocol: xen/interface/io/displif.h.

---
 drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
drivers/gpu/drm/xen/xen_drm_front.c +82 -0
index fd372fb464a1..d0306f9d660d 100644
@@ -24,19 +24,141 @@
 
 #include <xen/interface/io/displif.h>
 
+#include "xen_drm_front.h"
+
+static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
+{
+}
+
+static int backend_on_initwait(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static int backend_on_connected(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static void backend_on_disconnected(struct xen_drm_front_info *front_info)
+{
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static void backend_on_changed(struct xenbus_device *xb_dev,
 		enum xenbus_state backend_state)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	DRM_DEBUG("Backend state is %s, front is %s\n",
+			xenbus_strstate(backend_state),
+			xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		if (xb_dev->state != XenbusStateInitialising)
+			break;
+
+		ret = backend_on_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = backend_on_connected(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		backend_on_disconnected(front_info);
+		break;
+	}
 }
 

drivers/gpu/drm/xen/xen_drm_front.c line 122

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c +6 -1
 static int xen_drv_probe(struct xenbus_device *xb_dev,
 		const struct xenbus_device_id *id)
 {
-	return 0;
+	struct xen_drm_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+			sizeof(*front_info), GFP_KERNEL);
+	if (!front_info) {
+		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");

No need for message in case of allocation failure: this is handled in memory allocation already.

Juergen

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#23 lore raw

Re: [PATCH 2/9] drm/xen-front: Implement Xen bus state handling

Quoted 110 lines · Juergen Gross
Quoted 109 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to the state diagram and recovery flow from display para-virtualized
protocol: xen/interface/io/displif.h.

---
  drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
  drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
  2 files changed, 149 insertions(+), 1 deletion(-)

create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h

drivers/gpu/drm/xen/xen_drm_front.c +82 -0
index fd372fb464a1..d0306f9d660d 100644
@@ -24,19 +24,141 @@
 
  #include <xen/interface/io/displif.h>
 
+#include "xen_drm_front.h"
+
+static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
+{
+}
+
+static int backend_on_initwait(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static int backend_on_connected(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static void backend_on_disconnected(struct xen_drm_front_info *front_info)
+{
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
  static void backend_on_changed(struct xenbus_device *xb_dev,
  		enum xenbus_state backend_state)
  {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	DRM_DEBUG("Backend state is %s, front is %s\n",
+			xenbus_strstate(backend_state),
+			xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		if (xb_dev->state != XenbusStateInitialising)
+			break;
+
+		ret = backend_on_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = backend_on_connected(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		backend_on_disconnected(front_info);
+		break;
+	}
  }
 
Quoted 12 lines

drivers/gpu/drm/xen/xen_drm_front.c line 122

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c +6 -1
  static int xen_drv_probe(struct xenbus_device *xb_dev,
  		const struct xenbus_device_id *id)
  {
-	return 0;
+	struct xen_drm_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+			sizeof(*front_info), GFP_KERNEL);
+	if (!front_info) {
+		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");

No need for message in case of allocation failure: this is handled in memory allocation already.

Will remove, thank you

Quoted 2 lines

Juergen

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#24 lore raw

PATCH 2/9 drm/xen-front: Implement Xen bus state handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to the state diagram and recovery flow from display para-virtualized
protocol: xen/interface/io/displif.h.

---
 drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
drivers/gpu/drm/xen/xen_drm_front.c +123 -1
index fd372fb464a1..d0306f9d660d 100644
@@ -24,19 +24,141 @@
 
 #include <xen/interface/io/displif.h>
 
+#include "xen_drm_front.h"
+
+static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
+{
+}
+
+static int backend_on_initwait(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static int backend_on_connected(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static void backend_on_disconnected(struct xen_drm_front_info *front_info)
+{
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static void backend_on_changed(struct xenbus_device *xb_dev,
 		enum xenbus_state backend_state)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	DRM_DEBUG("Backend state is %s, front is %s\n",
+			xenbus_strstate(backend_state),
+			xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		if (xb_dev->state != XenbusStateInitialising)
+			break;
+
+		ret = backend_on_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = backend_on_connected(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		backend_on_disconnected(front_info);
+		break;
+	}
 }
 
 static int xen_drv_probe(struct xenbus_device *xb_dev,
 		const struct xenbus_device_id *id)
 {
-	return 0;
+	struct xen_drm_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+			sizeof(*front_info), GFP_KERNEL);
+	if (!front_info) {
+		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");
+		return -ENOMEM;
+	}
+
+	front_info->xb_dev = xb_dev;
+	dev_set_drvdata(&xb_dev->dev, front_info);
+	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
 
 static int xen_drv_remove(struct xenbus_device *dev)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev);
+	int to = 100;
+
+	xenbus_switch_state(dev, XenbusStateClosing);
+
+	/*
+	 * On driver removal it is disconnected from XenBus,
+	 * so no backend state change events come via .otherend_changed
+	 * callback. This prevents us from exiting gracefully, e.g.
+	 * signaling the backend to free event channels, waiting for its
+	 * state to change to XenbusStateClosed and cleaning at our end.
+	 * Normally when front driver removed backend will finally go into
+	 * XenbusStateInitWait state.
+	 *
+	 * Workaround: read backend's state manually and wait with time-out.
+	 */
+	while ((xenbus_read_unsigned(front_info->xb_dev->otherend,
+			"state", XenbusStateUnknown) != XenbusStateInitWait) &&
+			to--)
+		msleep(10);
+
+	if (!to)
+		DRM_ERROR("Backend state is %s while removing driver\n",
+			xenbus_strstate(xenbus_read_unsigned(
+					front_info->xb_dev->otherend,
+					"state", XenbusStateUnknown)));
+
+	xen_drv_remove_internal(front_info);
+	xenbus_frontend_closed(dev);
 	return 0;
 }
 
drivers/gpu/drm/xen/xen_drm_front.h new file +26 -0
new file mode 100644
index 000000000000..8af46850f126
@@ -0,0 +1,26 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_H_
+#define __XEN_DRM_FRONT_H_
+
+struct xen_drm_front_info {
+	struct xenbus_device *xb_dev;
+};
+
+#endif /* __XEN_DRM_FRONT_H_ */
Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#25 lore raw

PATCH 3/9 drm/xen-front: Read driver configuration from Xen store

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Read configuration values from Xen store according to xen/interface/io/displif.h protocol:
- read connector(s) configuration
- read buffer allocation mode (backend/frontend)

---
 drivers/gpu/drm/xen/Makefile            |  3 +-
 drivers/gpu/drm/xen/xen_drm_front.c     |  9 ++++
 drivers/gpu/drm/xen/xen_drm_front.h     |  3 ++
 drivers/gpu/drm/xen/xen_drm_front_cfg.c | 84 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_cfg.h | 45 ++++++++++++++++++
 5 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.h
drivers/gpu/drm/xen/Makefile +2 -1
index 967074d348f6..0a2eae757f0c 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-drm_xen_front-objs := xen_drm_front.o
+drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +9 -0
index d0306f9d660d..0a90c474c7ce 100644
@@ -32,6 +32,15 @@ static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 
 static int backend_on_initwait(struct xen_drm_front_info *front_info)
 {
+	struct xen_drm_front_cfg *cfg = &front_info->cfg;
+	int ret;
+
+	cfg->front_info = front_info;
+	ret = xen_drm_front_cfg_card(front_info, cfg);
+	if (ret < 0)
+		return ret;
+
+	DRM_INFO("Have %d conector(s)\n", cfg->num_connectors);
 	return 0;
 }
 
drivers/gpu/drm/xen/xen_drm_front.h +3 -0
index 8af46850f126..62b0d4e3e12b 100644
@@ -19,8 +19,11 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include "xen_drm_front_cfg.h"
+
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
+	struct xen_drm_front_cfg cfg;
 };
 
 #endif /* __XEN_DRM_FRONT_H_ */
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +84 -0

84 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_cfg.h new file +45 -0

45 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#26 lore raw

Re: [PATCH 3/9] drm/xen-front: Read driver configuration from Xen store

Quoted 9 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +9 -0
+
+static int cfg_connector(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_cfg_connector *connector,
+		const char *path, int index)
+{
+	char *connector_path;
+
+	connector_path = devm_kasprintf(&front_info->xb_dev->dev,
+			GFP_KERNEL, "%s/%d", path, index);

drivers/gpu/drm/xen/xen_drm_front_cfg.c line 46

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +10 -0
+	if (!connector_path)
+		return -ENOMEM;
+
+	connector->xenstore_path = connector_path;
+	if (xenbus_scanf(XBT_NIL, connector_path, XENDISPL_FIELD_RESOLUTION,
+			"%d" XENDISPL_RESOLUTION_SEPARATOR "%d",
+			&connector->width, &connector->height) < 0) {
+		/* either no entry configured or wrong resolution set */
+		connector->width = 0;
+		connector->height = 0;

Do you also need to set connector->xenstore_path to NULL? Or maybe just set it after xenbus_scanf() call.

-boris

#27 lore raw

Re: [PATCH 3/9] drm/xen-front: Read driver configuration from Xen store

Quoted 14 lines · Boris Ostrovsky
Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +13 -0
+
+static int cfg_connector(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_cfg_connector *connector,
+		const char *path, int index)
+{
+	char *connector_path;
+
+	connector_path = devm_kasprintf(&front_info->xb_dev->dev,
+			GFP_KERNEL, "%s/%d", path, index);
+	if (!connector_path)
+		return -ENOMEM;
+
+	connector->xenstore_path = connector_path;
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_cfg.c line 46

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +6 -0
+	if (xenbus_scanf(XBT_NIL, connector_path, XENDISPL_FIELD_RESOLUTION,
+			"%d" XENDISPL_RESOLUTION_SEPARATOR "%d",
+			&connector->width, &connector->height) < 0) {
+		/* either no entry configured or wrong resolution set */
+		connector->width = 0;
+		connector->height = 0;

Do you also need to set connector->xenstore_path to NULL? Or maybe just set it after xenbus_scanf() call.

Will move it down the code, after "if", thank you

Quoted 4 lines

-boris

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#28 lore raw

Re: [PATCH 3/9] drm/xen-front: Read driver configuration from Xen store

In reply to Boris Ostrovsky
Quoted 14 lines · Boris Ostrovsky
Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +13 -0
+
+static int cfg_connector(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_cfg_connector *connector,
+		const char *path, int index)
+{
+	char *connector_path;
+
+	connector_path = devm_kasprintf(&front_info->xb_dev->dev,
+			GFP_KERNEL, "%s/%d", path, index);
+	if (!connector_path)
+		return -ENOMEM;
+
+	connector->xenstore_path = connector_path;
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_cfg.c line 46

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +6 -0
+	if (xenbus_scanf(XBT_NIL, connector_path, XENDISPL_FIELD_RESOLUTION,
+			"%d" XENDISPL_RESOLUTION_SEPARATOR "%d",
+			&connector->width, &connector->height) < 0) {
+		/* either no entry configured or wrong resolution set */
+		connector->width = 0;
+		connector->height = 0;

Do you also need to set connector->xenstore_path to NULL? Or maybe just set it after xenbus_scanf() call.

Will move it down the code, after "if", thank you

Quoted 4 lines

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#29 lore raw

PATCH 3/9 drm/xen-front: Read driver configuration from Xen store

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Read configuration values from Xen store according to xen/interface/io/displif.h protocol:
- read connector(s) configuration
- read buffer allocation mode (backend/frontend)

---
 drivers/gpu/drm/xen/Makefile            |  3 +-
 drivers/gpu/drm/xen/xen_drm_front.c     |  9 ++++
 drivers/gpu/drm/xen/xen_drm_front.h     |  3 ++
 drivers/gpu/drm/xen/xen_drm_front_cfg.c | 84 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_cfg.h | 45 ++++++++++++++++++
 5 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_cfg.h
drivers/gpu/drm/xen/Makefile +2 -1
index 967074d348f6..0a2eae757f0c 100644
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-drm_xen_front-objs := xen_drm_front.o
+drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +9 -0
index d0306f9d660d..0a90c474c7ce 100644
@@ -32,6 +32,15 @@ static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 
 static int backend_on_initwait(struct xen_drm_front_info *front_info)
 {
+	struct xen_drm_front_cfg *cfg = &front_info->cfg;
+	int ret;
+
+	cfg->front_info = front_info;
+	ret = xen_drm_front_cfg_card(front_info, cfg);
+	if (ret < 0)
+		return ret;
+
+	DRM_INFO("Have %d conector(s)\n", cfg->num_connectors);
 	return 0;
 }
 
drivers/gpu/drm/xen/xen_drm_front.h +3 -0
index 8af46850f126..62b0d4e3e12b 100644
@@ -19,8 +19,11 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include "xen_drm_front_cfg.h"
+
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
+	struct xen_drm_front_cfg cfg;
 };
 
 #endif /* __XEN_DRM_FRONT_H_ */
drivers/gpu/drm/xen/xen_drm_front_cfg.c new file +84 -0

84 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_cfg.h new file +45 -0

45 lines not on this page · raw message

Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#30 lore raw

PATCH 4/9 drm/xen-front: Implement Xen event channel handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Handle Xen event channels:
- create for all configured connectors and publish corresponding ring references and event channels in Xen store, so backend can connect
- implement event channels interrupt handlers
- create and destroy event channels with respect to Xen bus state

---
 drivers/gpu/drm/xen/Makefile                |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c         |  16 +-
 drivers/gpu/drm/xen/xen_drm_front.h         |  22 ++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c | 399 ++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h |  89 +++++++
 5 files changed, 526 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h
drivers/gpu/drm/xen/Makefile +1 -0
index 0a2eae757f0c..4ce7756b8437 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +15 -1
index 0a90c474c7ce..b558e0ae3b33 100644
@@ -25,9 +25,15 @@
 #include <xen/interface/io/displif.h>
 
 #include "xen_drm_front.h"
+#include "xen_drm_front_evtchnl.h"
+
+static struct xen_drm_front_ops front_ops = {
+	/* placeholder for now */
+};
 
 static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_free_all(front_info);
 }
 
 static int backend_on_initwait(struct xen_drm_front_info *front_info)
@@ -41,16 +47,23 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
 		return ret;
 
 	DRM_INFO("Have %d conector(s)\n", cfg->num_connectors);
-	return 0;
+	/* Create event channels for all connectors and publish */
+	ret = xen_drm_front_evtchnl_create_all(front_info, &front_ops);
+	if (ret < 0)
+		return ret;
+
+	return xen_drm_front_evtchnl_publish_all(front_info);
 }
 
 static int backend_on_connected(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
 	return 0;
 }
 
 static void backend_on_disconnected(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
 	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
 }
 
@@ -133,6 +146,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 	}
 
 	front_info->xb_dev = xb_dev;
+	spin_lock_init(&front_info->io_lock);
 	dev_set_drvdata(&xb_dev->dev, front_info);
 	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
drivers/gpu/drm/xen/xen_drm_front.h +22 -0
index 62b0d4e3e12b..13f22736ae02 100644
@@ -21,8 +21,30 @@
 
 #include "xen_drm_front_cfg.h"
 
+#ifndef GRANT_INVALID_REF
+/*
+ * Note on usage of grant reference 0 as invalid grant reference:
+ * grant reference 0 is valid, but never exposed to a PV driver,
+ * because of the fact it is already in use/reserved by the PV console.
+ */
+#define GRANT_INVALID_REF	0
+#endif
+
+struct xen_drm_front_ops {
+	/* CAUTION! this is called with a spin_lock held! */
+	void (*on_frame_done)(struct platform_device *pdev,
+			int conn_idx, uint64_t fb_cookie);
+};
+
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
+	/* to protect data between backend IO code and interrupt handler */
+	spinlock_t io_lock;
+	/* virtual DRM platform device */
+	struct platform_device *drm_pdev;
+
+	int num_evt_pairs;
+	struct xen_drm_front_evtchnl_pair *evt_pairs;
 	struct xen_drm_front_cfg cfg;
 };
 
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +399 -0

399 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_evtchnl.h new file +89 -0

89 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#31 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+	struct xen_drm_front_evtchnl *evtchnl = dev_id;
+	struct xen_drm_front_info *front_info = evtchnl->front_info;
+	struct xendispl_resp *resp;
+	RING_IDX i, rp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&front_info->io_lock, flags);
+
+	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+		goto out;

Do you need to check the state under lock? (in other routines too).

...

Quoted 27 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +27 -0
+
+static void evtchnl_free(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_evtchnl *evtchnl)
+{
+	unsigned long page = 0;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		page = (unsigned long)evtchnl->u.req.ring.sring;
+	else if (evtchnl->type == EVTCHNL_TYPE_EVT)
+		page = (unsigned long)evtchnl->u.evt.page;
+	if (!page)
+		return;
+
+	evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ) {
+		/* release all who still waits for response if any */
+		evtchnl->u.req.resp_status = -EIO;
+		complete_all(&evtchnl->u.req.completion);
+	}
+
+	if (evtchnl->irq)
+		unbind_from_irqhandler(evtchnl->irq, evtchnl);
+
+	if (evtchnl->port)
+		xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
+

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 166

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +10 -0
+	/* end access and free the page */
+	if (evtchnl->gref != GRANT_INVALID_REF)
+		gnttab_end_foreign_access(evtchnl->gref, 0, page);
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		evtchnl->u.req.ring.sring = NULL;
+	else
+		evtchnl->u.evt.page = NULL;
+
+	memset(evtchnl, 0, sizeof(*evtchnl));

Since you are zeroing out the structure you don't need to set fields to zero.

I also think you need to free the page.

-boris

#32 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

Quoted 15 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+	struct xen_drm_front_evtchnl *evtchnl = dev_id;
+	struct xen_drm_front_info *front_info = evtchnl->front_info;
+	struct xendispl_resp *resp;
+	RING_IDX i, rp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&front_info->io_lock, flags);
+
+	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+		goto out;

Do you need to check the state under lock? (in other routines too).

not really, will move out of the lock in interrupt handlers other places (I assume you refer to be_stream_do_io) it is set under lock as a part of atomic operation, e.g. we get a new request pointer from the ring and reset completion So, those places still seem to be ok

Quoted 33 lines

...

Quoted 31 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +31 -0
+
+static void evtchnl_free(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_evtchnl *evtchnl)
+{
+	unsigned long page = 0;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		page = (unsigned long)evtchnl->u.req.ring.sring;
+	else if (evtchnl->type == EVTCHNL_TYPE_EVT)
+		page = (unsigned long)evtchnl->u.evt.page;
+	if (!page)
+		return;
+
+	evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ) {
+		/* release all who still waits for response if any */
+		evtchnl->u.req.resp_status = -EIO;
+		complete_all(&evtchnl->u.req.completion);
+	}
+
+	if (evtchnl->irq)
+		unbind_from_irqhandler(evtchnl->irq, evtchnl);
+
+	if (evtchnl->port)
+		xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
+
+	/* end access and free the page */
+	if (evtchnl->gref != GRANT_INVALID_REF)
+		gnttab_end_foreign_access(evtchnl->gref, 0, page);
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 166

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +6 -0
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		evtchnl->u.req.ring.sring = NULL;
+	else
+		evtchnl->u.evt.page = NULL;
+
+	memset(evtchnl, 0, sizeof(*evtchnl));

Since you are zeroing out the structure you don't need to set fields to zero.

good catch, thank you

Quoted 1 line

I also think you need to free the page.

it is freed by gnttab_end_foreign_access, please see [1]

Quoted 1 line

-boris

[1] https://elixir.bootlin.com/linux/v4.11-rc1/source/drivers/xen/grant-table.c#L380
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#33 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

Quoted 16 lines · Oleksandr Andrushchenko
Quoted 15 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+    struct xen_drm_front_evtchnl *evtchnl = dev_id;
+    struct xen_drm_front_info *front_info = evtchnl->front_info;
+    struct xendispl_resp *resp;
+    RING_IDX i, rp;
+    unsigned long flags;
+
+    spin_lock_irqsave(&front_info->io_lock, flags);
+
+    if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+        goto out;

Do you need to check the state under lock? (in other routines too).

Quoted 2 lines

not really, will move out of the lock in interrupt handlers other places (I assume you refer to be_stream_do_io)

I was mostly referring to evtchnl_interrupt_evt().

-boris

Quoted 3 lines

it is set under lock as a part of atomic operation, e.g. we get a new request pointer from the ring and reset completion So, those places still seem to be ok

#34 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

Quoted 17 lines · Boris Ostrovsky
Quoted 16 lines · Oleksandr Andrushchenko
Quoted 15 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+    struct xen_drm_front_evtchnl *evtchnl = dev_id;
+    struct xen_drm_front_info *front_info = evtchnl->front_info;
+    struct xendispl_resp *resp;
+    RING_IDX i, rp;
+    unsigned long flags;
+
+    spin_lock_irqsave(&front_info->io_lock, flags);
+
+    if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+        goto out;

Do you need to check the state under lock? (in other routines too).

Quoted 4 lines
Quoted 2 lines

not really, will move out of the lock in interrupt handlers other places (I assume you refer to be_stream_do_io)

I was mostly referring to evtchnl_interrupt_evt().

ah, then we are on the same page: I will move the check in interrupt handlers

Quoted 6 lines

-boris

Quoted 3 lines

it is set under lock as a part of atomic operation, e.g. we get a new request pointer from the ring and reset completion So, those places still seem to be ok

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#35 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

In reply to Boris Ostrovsky
Quoted 17 lines · Boris Ostrovsky
Quoted 16 lines · Oleksandr Andrushchenko
Quoted 15 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+    struct xen_drm_front_evtchnl *evtchnl = dev_id;
+    struct xen_drm_front_info *front_info = evtchnl->front_info;
+    struct xendispl_resp *resp;
+    RING_IDX i, rp;
+    unsigned long flags;
+
+    spin_lock_irqsave(&front_info->io_lock, flags);
+
+    if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+        goto out;

Do you need to check the state under lock? (in other routines too).

Quoted 4 lines
Quoted 2 lines

not really, will move out of the lock in interrupt handlers other places (I assume you refer to be_stream_do_io)

I was mostly referring to evtchnl_interrupt_evt().

ah, then we are on the same page: I will move the check in interrupt handlers

Quoted 6 lines

-boris

Quoted 3 lines

it is set under lock as a part of atomic operation, e.g. we get a new request pointer from the ring and reset completion So, those places still seem to be ok

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#36 lore raw

Re: [PATCH 4/9] drm/xen-front: Implement Xen event channel handling

In reply to Boris Ostrovsky
Quoted 15 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 42

Quoted 13 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +13 -0
+
+static irqreturn_t evtchnl_interrupt_ctrl(int irq, void *dev_id)
+{
+	struct xen_drm_front_evtchnl *evtchnl = dev_id;
+	struct xen_drm_front_info *front_info = evtchnl->front_info;
+	struct xendispl_resp *resp;
+	RING_IDX i, rp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&front_info->io_lock, flags);
+
+	if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED))
+		goto out;

Do you need to check the state under lock? (in other routines too).

not really, will move out of the lock in interrupt handlers other places (I assume you refer to be_stream_do_io) it is set under lock as a part of atomic operation, e.g. we get a new request pointer from the ring and reset completion So, those places still seem to be ok

Quoted 33 lines

...

Quoted 31 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +31 -0
+
+static void evtchnl_free(struct xen_drm_front_info *front_info,
+		struct xen_drm_front_evtchnl *evtchnl)
+{
+	unsigned long page = 0;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		page = (unsigned long)evtchnl->u.req.ring.sring;
+	else if (evtchnl->type == EVTCHNL_TYPE_EVT)
+		page = (unsigned long)evtchnl->u.evt.page;
+	if (!page)
+		return;
+
+	evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
+
+	if (evtchnl->type == EVTCHNL_TYPE_REQ) {
+		/* release all who still waits for response if any */
+		evtchnl->u.req.resp_status = -EIO;
+		complete_all(&evtchnl->u.req.completion);
+	}
+
+	if (evtchnl->irq)
+		unbind_from_irqhandler(evtchnl->irq, evtchnl);
+
+	if (evtchnl->port)
+		xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
+
+	/* end access and free the page */
+	if (evtchnl->gref != GRANT_INVALID_REF)
+		gnttab_end_foreign_access(evtchnl->gref, 0, page);
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_evtchnl.c line 166

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +6 -0
+	if (evtchnl->type == EVTCHNL_TYPE_REQ)
+		evtchnl->u.req.ring.sring = NULL;
+	else
+		evtchnl->u.evt.page = NULL;
+
+	memset(evtchnl, 0, sizeof(*evtchnl));

Since you are zeroing out the structure you don't need to set fields to zero.

good catch, thank you

Quoted 1 line

I also think you need to free the page.

it is freed by gnttab_end_foreign_access, please see [1]

Quoted 1 line

-boris

[1] https://elixir.bootlin.com/linux/v4.11-rc1/source/drivers/xen/grant-table.c#L380

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#37 lore raw

PATCH 4/9 drm/xen-front: Implement Xen event channel handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Handle Xen event channels:
- create for all configured connectors and publish corresponding ring references and event channels in Xen store, so backend can connect
- implement event channels interrupt handlers
- create and destroy event channels with respect to Xen bus state

---
 drivers/gpu/drm/xen/Makefile                |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c         |  16 +-
 drivers/gpu/drm/xen/xen_drm_front.h         |  22 ++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c | 399 ++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h |  89 +++++++
 5 files changed, 526 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_evtchnl.h
drivers/gpu/drm/xen/Makefile +1 -0
index 0a2eae757f0c..4ce7756b8437 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +15 -1
index 0a90c474c7ce..b558e0ae3b33 100644
@@ -25,9 +25,15 @@
 #include <xen/interface/io/displif.h>
 
 #include "xen_drm_front.h"
+#include "xen_drm_front_evtchnl.h"
+
+static struct xen_drm_front_ops front_ops = {
+	/* placeholder for now */
+};
 
 static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_free_all(front_info);
 }
 
 static int backend_on_initwait(struct xen_drm_front_info *front_info)
@@ -41,16 +47,23 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
 		return ret;
 
 	DRM_INFO("Have %d conector(s)\n", cfg->num_connectors);
-	return 0;
+	/* Create event channels for all connectors and publish */
+	ret = xen_drm_front_evtchnl_create_all(front_info, &front_ops);
+	if (ret < 0)
+		return ret;
+
+	return xen_drm_front_evtchnl_publish_all(front_info);
 }
 
 static int backend_on_connected(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
 	return 0;
 }
 
 static void backend_on_disconnected(struct xen_drm_front_info *front_info)
 {
+	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
 	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
 }
 
@@ -133,6 +146,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 	}
 
 	front_info->xb_dev = xb_dev;
+	spin_lock_init(&front_info->io_lock);
 	dev_set_drvdata(&xb_dev->dev, front_info);
 	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
drivers/gpu/drm/xen/xen_drm_front.h +22 -0
index 62b0d4e3e12b..13f22736ae02 100644
@@ -21,8 +21,30 @@
 
 #include "xen_drm_front_cfg.h"
 
+#ifndef GRANT_INVALID_REF
+/*
+ * Note on usage of grant reference 0 as invalid grant reference:
+ * grant reference 0 is valid, but never exposed to a PV driver,
+ * because of the fact it is already in use/reserved by the PV console.
+ */
+#define GRANT_INVALID_REF	0
+#endif
+
+struct xen_drm_front_ops {
+	/* CAUTION! this is called with a spin_lock held! */
+	void (*on_frame_done)(struct platform_device *pdev,
+			int conn_idx, uint64_t fb_cookie);
+};
+
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
+	/* to protect data between backend IO code and interrupt handler */
+	spinlock_t io_lock;
+	/* virtual DRM platform device */
+	struct platform_device *drm_pdev;
+
+	int num_evt_pairs;
+	struct xen_drm_front_evtchnl_pair *evt_pairs;
 	struct xen_drm_front_cfg cfg;
 };
 
drivers/gpu/drm/xen/xen_drm_front_evtchnl.c new file +399 -0

399 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_evtchnl.h new file +89 -0

89 lines not on this page · raw message

Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#38 lore raw

PATCH 5/9 drm/xen-front: Implement handling of shared display buffers

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement shared buffer handling according to the para-virtualized display device protocol at xen/interface/io/displif.h:
- handle page directories according to displif protocol:
- allocate and share page directories
- grant references to the required set of pages for the page directory
- allocate xen balllooned pages via Xen balloon driver with alloc_xenballooned_pages/free_xenballooned_pages
- grant references to the required set of pages for the shared buffer itself
- implement pages map/unmap for the buffers allocated by the backend (gnttab_map_refs/gnttab_unmap_refs)

---
 drivers/gpu/drm/xen/Makefile              |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c       |   4 +
 drivers/gpu/drm/xen/xen_drm_front_shbuf.c | 430 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_shbuf.h |  80 ++++++
 4 files changed, 515 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.h
drivers/gpu/drm/xen/Makefile +1 -0
index 4ce7756b8437..f1823cb596c5 100644
@@ -2,6 +2,7 @@
 
 drm_xen_front-objs := xen_drm_front.o \
 		      xen_drm_front_evtchnl.o \
+		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +4 -0
index b558e0ae3b33..0d94ff272da3 100644
@@ -26,6 +26,7 @@
 
 #include "xen_drm_front.h"
 #include "xen_drm_front_evtchnl.h"
+#include "xen_drm_front_shbuf.h"
 
 static struct xen_drm_front_ops front_ops = {
 	/* placeholder for now */
@@ -199,6 +200,9 @@ static struct xenbus_driver xen_driver = {
 
 static int __init xen_drv_init(void)
 {
+	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */
+	BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);
+
 	if (!xen_domain())
 		return -ENODEV;
 
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +430 -0

430 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_shbuf.h new file +80 -0

80 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#39 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

drivers/gpu/drm/xen/xen_drm_front.c static struct xenbus_driver xen_driver = { · line 204

Quoted 5 lines · Oleksandr Andrushchenko

static int __init xen_drv_init(void)
{

drivers/gpu/drm/xen/xen_drm_front.c +2 -0
+	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */
+	BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 187

Quoted 2 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+	ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+	BUG_ON(ret);

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

Quoted 11 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +11 -0
+
+static int alloc_storage(struct xen_drm_front_shbuf *buf)
+{
+	if (buf->sgt) {
+		buf->pages = kvmalloc_array(buf->num_pages,
+				sizeof(struct page *), GFP_KERNEL);
+		if (!buf->pages)
+			return -ENOMEM;
+
+		if (drm_prime_sg_to_page_addr_arrays(buf->sgt, buf->pages,
+				NULL, buf->num_pages) < 0)

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 367

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +10 -0
+			return -EINVAL;
+	}
+
+	buf->grefs = kcalloc(buf->num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
+	if (!buf->grefs)
+		return -ENOMEM;
+
+	buf->directory = kcalloc(get_num_pages_dir(buf), PAGE_SIZE, GFP_KERNEL);
+	if (!buf->directory)
+		return -ENOMEM;

You need to clean up on errors.

-boris

Quoted 3 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +3 -0
+
+	return 0;
+}
#40 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

Quoted 10 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front.c static struct xenbus_driver xen_driver = { · line 204

Quoted 5 lines · Oleksandr Andrushchenko
  
  static int __init xen_drv_init(void)
  {
drivers/gpu/drm/xen/xen_drm_front.c +2 -0
+	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */
+	BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

This is a compile time check, so if kernel/Xen is configured to use page size combination which is not supported by the driver it will fail during compilation. This seems correct to me, because you shouldn't even try to load the driver which cannot handle different page sizes to not make any harm.

Quoted 9 lines

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 187

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+	ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+	BUG_ON(ret);

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

I will rework BUG_* for map/unmap code to handle errors, but will still leave
    /* either pages or sgt, not both */ BUG_ON(cfg->pages && cfg->sgt);
which is a real driver bug and must not happen

Quoted 17 lines
Quoted 17 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +14 -0
+
+static int alloc_storage(struct xen_drm_front_shbuf *buf)
+{
+	if (buf->sgt) {
+		buf->pages = kvmalloc_array(buf->num_pages,
+				sizeof(struct page *), GFP_KERNEL);
+		if (!buf->pages)
+			return -ENOMEM;
+
+		if (drm_prime_sg_to_page_addr_arrays(buf->sgt, buf->pages,
+				NULL, buf->num_pages) < 0)
+			return -EINVAL;
+	}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 367

Quoted 7 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +7 -0
+	buf->grefs = kcalloc(buf->num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
+	if (!buf->grefs)
+		return -ENOMEM;
+
+	buf->directory = kcalloc(get_num_pages_dir(buf), PAGE_SIZE, GFP_KERNEL);
+	if (!buf->directory)
+		return -ENOMEM;

You need to clean up on errors.

this is called in xen_drm_front_shbuf_alloc and is properly cleaned on failure, e.g.:
    ret = alloc_storage(buf);
    if (ret)
        goto fail;
[...]
fail:
    xen_drm_front_shbuf_free(buf);

Quoted 5 lines

-boris

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 70

Quoted 3 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +3 -0
+
+	return 0;
+}

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#41 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

Quoted 12 lines · Oleksandr Andrushchenko
Quoted 11 lines · Boris Ostrovsky
Quoted 5 lines · Oleksandr Andrushchenko

static int __init xen_drv_init(void)
{
+ /* At the moment we only support case with XEN_PAGE_SIZE ==
PAGE_SIZE */
+ BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

Quoted 5 lines

This is a compile time check, so if kernel/Xen is configured to use page size combination which is not supported by the driver it will fail during compilation. This seems correct to me, because you shouldn't even try to load the driver which cannot handle different page sizes to not make any harm.

This will prevent whole kernel from building. So, for example, randconfig builds will fail.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+    ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+    BUG_ON(ret);
Quoted 8 lines
Quoted 3 lines

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

I will rework BUG_* for map/unmap code to handle errors, but will still leave

    /* either pages or sgt, not both */
    BUG_ON(cfg->pages && cfg->sgt);

which is a real driver bug and must not happen

Why not return an error?

In fact, AFAICS you only call it in patch 9 where both of these can be tested, in which case something like -EINVAL would look reasonable.

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#42 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

Quoted 12 lines · Boris Ostrovsky
Quoted 11 lines · Oleksandr Andrushchenko
Quoted 10 lines · Boris Ostrovsky
Quoted 5 lines · Oleksandr Andrushchenko

static int __init xen_drv_init(void)
{
+ /* At the moment we only support case with XEN_PAGE_SIZE ==
PAGE_SIZE */
+ BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

Quoted 9 lines
Quoted 5 lines

This is a compile time check, so if kernel/Xen is configured to use page size combination which is not supported by the driver it will fail during compilation. This seems correct to me, because you shouldn't even try to load the driver which cannot handle different page sizes to not make any harm.

This will prevent whole kernel from building. So, for example, randconfig builds will fail.

makes a lot of sense, thank you
will rework so I reject to load if the requirement is not met

Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+    ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+    BUG_ON(ret);
Quoted 8 lines
Quoted 3 lines

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

I will rework BUG_* for map/unmap code to handle errors, but will still leave

     /* either pages or sgt, not both */
     BUG_ON(cfg->pages && cfg->sgt);

which is a real driver bug and must not happen

Quoted 4 lines

Why not return an error?

In fact, AFAICS you only call it in patch 9 where both of these can be tested, in which case something like -EINVAL would look reasonable.

ok, will remove BUG_ON as well

Quoted 1 line

-boris

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#43 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

In reply to Boris Ostrovsky
Quoted 12 lines · Boris Ostrovsky
Quoted 11 lines · Oleksandr Andrushchenko
Quoted 10 lines · Boris Ostrovsky
Quoted 5 lines · Oleksandr Andrushchenko

static int __init xen_drv_init(void)
{
+ /* At the moment we only support case with XEN_PAGE_SIZE ==
PAGE_SIZE */
+ BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

Quoted 9 lines
Quoted 5 lines

This is a compile time check, so if kernel/Xen is configured to use page size combination which is not supported by the driver it will fail during compilation. This seems correct to me, because you shouldn't even try to load the driver which cannot handle different page sizes to not make any harm.

This will prevent whole kernel from building. So, for example, randconfig builds will fail.

makes a lot of sense, thank you
will rework so I reject to load if the requirement is not met

Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+    ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+    BUG_ON(ret);
Quoted 8 lines
Quoted 3 lines

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

I will rework BUG_* for map/unmap code to handle errors, but will still leave

     /* either pages or sgt, not both */
     BUG_ON(cfg->pages && cfg->sgt);

which is a real driver bug and must not happen

Quoted 4 lines

Why not return an error?

In fact, AFAICS you only call it in patch 9 where both of these can be tested, in which case something like -EINVAL would look reasonable.

ok, will remove BUG_ON as well

Quoted 1 line

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#44 lore raw

Re: [PATCH 5/9] drm/xen-front: Implement handling of shared display buffers

In reply to Boris Ostrovsky
Quoted 10 lines · Boris Ostrovsky

drivers/gpu/drm/xen/xen_drm_front.c static struct xenbus_driver xen_driver = { · line 204

Quoted 5 lines · Oleksandr Andrushchenko
  
  static int __init xen_drv_init(void)
  {
drivers/gpu/drm/xen/xen_drm_front.c +2 -0
+	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */
+	BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);

Why BUILD_BUG_ON? This should simply not load if page sizes are different.

This is a compile time check, so if kernel/Xen is configured to use page size combination which is not supported by the driver it will fail during compilation. This seems correct to me, because you shouldn't even try to load the driver which cannot handle different page sizes to not make any harm.

Quoted 9 lines

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 187

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +2 -0
+	ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
+	BUG_ON(ret);

We should try not to BUG*(). There are a few in this patch (and possibly others) that I think can be avoided.

I will rework BUG_* for map/unmap code to handle errors, but will still leave
    /* either pages or sgt, not both */ BUG_ON(cfg->pages && cfg->sgt);
which is a real driver bug and must not happen

Quoted 17 lines
Quoted 17 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +14 -0
+
+static int alloc_storage(struct xen_drm_front_shbuf *buf)
+{
+	if (buf->sgt) {
+		buf->pages = kvmalloc_array(buf->num_pages,
+				sizeof(struct page *), GFP_KERNEL);
+		if (!buf->pages)
+			return -ENOMEM;
+
+		if (drm_prime_sg_to_page_addr_arrays(buf->sgt, buf->pages,
+				NULL, buf->num_pages) < 0)
+			return -EINVAL;
+	}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 367

Quoted 7 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +7 -0
+	buf->grefs = kcalloc(buf->num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
+	if (!buf->grefs)
+		return -ENOMEM;
+
+	buf->directory = kcalloc(get_num_pages_dir(buf), PAGE_SIZE, GFP_KERNEL);
+	if (!buf->directory)
+		return -ENOMEM;

You need to clean up on errors.

this is called in xen_drm_front_shbuf_alloc and is properly cleaned on failure, e.g.:
    ret = alloc_storage(buf);
    if (ret)
        goto fail;
[...]
fail:
    xen_drm_front_shbuf_free(buf);

Quoted 5 lines

-boris

drivers/gpu/drm/xen/xen_drm_front_shbuf.c line 70

Quoted 3 lines
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +3 -0
+
+	return 0;
+}

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#45 lore raw

PATCH 5/9 drm/xen-front: Implement handling of shared display buffers

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement shared buffer handling according to the para-virtualized display device protocol at xen/interface/io/displif.h:
- handle page directories according to displif protocol:
- allocate and share page directories
- grant references to the required set of pages for the page directory
- allocate xen balllooned pages via Xen balloon driver with alloc_xenballooned_pages/free_xenballooned_pages
- grant references to the required set of pages for the shared buffer itself
- implement pages map/unmap for the buffers allocated by the backend (gnttab_map_refs/gnttab_unmap_refs)

---
 drivers/gpu/drm/xen/Makefile              |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c       |   4 +
 drivers/gpu/drm/xen/xen_drm_front_shbuf.c | 430 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_shbuf.h |  80 ++++++
 4 files changed, 515 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_shbuf.h
drivers/gpu/drm/xen/Makefile +1 -0
index 4ce7756b8437..f1823cb596c5 100644
@@ -2,6 +2,7 @@
 
 drm_xen_front-objs := xen_drm_front.o \
 		      xen_drm_front_evtchnl.o \
+		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
 
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.c +4 -0
index b558e0ae3b33..0d94ff272da3 100644
@@ -26,6 +26,7 @@
 
 #include "xen_drm_front.h"
 #include "xen_drm_front_evtchnl.h"
+#include "xen_drm_front_shbuf.h"
 
 static struct xen_drm_front_ops front_ops = {
 	/* placeholder for now */
@@ -199,6 +200,9 @@ static struct xenbus_driver xen_driver = {
 
 static int __init xen_drv_init(void)
 {
+	/* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */
+	BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);
+
 	if (!xen_domain())
 		return -ENODEV;
 
drivers/gpu/drm/xen/xen_drm_front_shbuf.c new file +430 -0

430 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_shbuf.h new file +80 -0

80 lines not on this page · raw message

Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#46 lore raw

PATCH 6/9 drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
 drivers/gpu/drm/xen/Makefile            |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
 5 files changed, 462 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h
drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
 		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +166 -3

206 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
 #include "xen_drm_front_cfg.h"
 
 #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
 #define GRANT_INVALID_REF	0
 #endif
 
+struct xen_drm_front_drm_pipeline;
+
 struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
 	/* CAUTION! this is called with a spin_lock held! */
 	void (*on_frame_done)(struct platform_device *pdev,
 			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
 };
 
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
 	/* to protect data between backend IO code and interrupt handler */
 	spinlock_t io_lock;
+	bool drm_pdrv_registered;
 	/* virtual DRM platform device */
 	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0

211 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0

60 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#47 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

Quoted 11 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +11 -0
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,

drivers/gpu/drm/xen/xen_drm_front_drv.c line 121

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +10 -0
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",

You must have been working on this for a while ;-)

I assume this needs to be updated.

Quoted 8 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +8 -0
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+

drivers/gpu/drm/xen/xen_drm_front_drv.c line 210

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +10 -0
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;

Would it be a problem, given the race, if you report that the frontend is not in use, while it actually is?

-boris

#48 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

Quoted 16 lines · Boris Ostrovsky
Quoted 14 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +14 -0
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_drv.c line 121

Quoted 7 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +7 -0
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",

You must have been working on this for a while ;-)

yes, this is true ;)

Quoted 2 lines

I assume this needs to be updated.

It can be, but I would either stick to the current value for historical reasons or would update it in the final version of the driver, so it reflects the date of issuing ;)

Quoted 12 lines
Quoted 12 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +12 -0
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_drv.c line 210

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +6 -0
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;

Would it be a problem, given the race, if you report that the frontend is not in use, while it actually is?

no, backend will not be able to activate us again

Quoted 1 line

-boris

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#49 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Boris Ostrovsky
Quoted 16 lines · Boris Ostrovsky
Quoted 14 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +14 -0
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_drv.c line 121

Quoted 7 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +7 -0
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",

You must have been working on this for a while ;-)

yes, this is true ;)

Quoted 2 lines

I assume this needs to be updated.

It can be, but I would either stick to the current value for historical reasons or would update it in the final version of the driver, so it reflects the date of issuing ;)

Quoted 12 lines
Quoted 12 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +12 -0
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_drv.c line 210

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +6 -0
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;

Would it be a problem, given the race, if you report that the frontend is not in use, while it actually is?

no, backend will not be able to activate us again

Quoted 1 line

-boris

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#50 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Oleksandr Andrushchenko
Quoted 122 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
 drivers/gpu/drm/xen/Makefile            |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
 5 files changed, 462 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h
drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
 		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +69 -0
index 0d94ff272da3..8de88e359d5e 100644
@@ -18,6 +18,8 @@
 
 #include <drm/drmP.h>
 
+#include <linux/of_device.h>
+
 #include <xen/platform_pci.h>
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -25,15 +27,161 @@
 #include <xen/interface/io/displif.h>
 
 #include "xen_drm_front.h"
+#include "xen_drm_front_drv.h"
 #include "xen_drm_front_evtchnl.h"
 #include "xen_drm_front_shbuf.h"
 
+static int be_mode_set(struct xen_drm_front_drm_pipeline *pipeline, uint32_t x,
+		uint32_t y, uint32_t width, uint32_t height, uint32_t bpp,
+		uint64_t fb_cookie)
+
+{
+	return 0;
+}
+
+static int be_dbuf_create_int(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages,
+		struct sg_table *sgt)
+{
+	return 0;
+}
+
+static int be_dbuf_create_from_sgt(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct sg_table *sgt)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, NULL, sgt);
+}
+
+static int be_dbuf_create_from_pages(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, pages, NULL);
+}
+
+static int be_dbuf_destroy(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie)
+{
+	return 0;
+}
+
+static int be_fb_attach(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint64_t fb_cookie, uint32_t width,
+		uint32_t height, uint32_t pixel_format)
+{
+	return 0;
+}
+
+static int be_fb_detach(struct xen_drm_front_info *front_info,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static int be_page_flip(struct xen_drm_front_info *front_info, int conn_idx,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static void xen_drm_drv_unload(struct xen_drm_front_info *front_info)
+{
+	if (front_info->xb_dev->state != XenbusStateReconfiguring)
+		return;
+
+	DRM_DEBUG("Can try removing driver now\n");
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static struct xen_drm_front_ops front_ops = {

drivers/gpu/drm/xen/xen_drm_front.c line 109

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c +9 -1
-	/* placeholder for now */
+	.mode_set = be_mode_set,
+	.dbuf_create_from_pages = be_dbuf_create_from_pages,
+	.dbuf_create_from_sgt = be_dbuf_create_from_sgt,
+	.dbuf_destroy = be_dbuf_destroy,
+	.fb_attach = be_fb_attach,
+	.fb_detach = be_fb_detach,
+	.page_flip = be_page_flip,
+	.drm_last_close = xen_drm_drv_unload,
+};

This looks like a midlayer/DRM-abstraction in your driver. Please remove, and instead directly hook your xen-front code into the relevant drm callbacks.

In general also pls make sure you don't implement dummy callbacks that do nothing, we've tried really hard to make them all optional in the drm infrastructure.
-Daniel

Quoted 458 lines
drivers/gpu/drm/xen/xen_drm_front.c +88 -2
+
+static int xen_drm_drv_probe(struct platform_device *pdev)
+{
+	/*
+	 * The device is not spawn from a device tree, so arch_setup_dma_ops
+	 * is not called, thus leaving the device with dummy DMA ops.
+	 * This makes the device return error on PRIME buffer import, which
+	 * is not correct: to fix this call of_dma_configure() with a NULL
+	 * node to set default DMA ops.
+	 */
+	of_dma_configure(&pdev->dev, NULL);
+	return xen_drm_front_drv_probe(pdev, &front_ops);
+}
+
+static int xen_drm_drv_remove(struct platform_device *pdev)
+{
+	return xen_drm_front_drv_remove(pdev);
+}
+
+struct platform_device_info xen_drm_front_platform_info = {
+	.name = XENDISPL_DRIVER_NAME,
+	.id = 0,
+	.num_res = 0,
+	.dma_mask = DMA_BIT_MASK(32),
 };
 
+static struct platform_driver xen_drm_front_front_info = {
+	.probe		= xen_drm_drv_probe,
+	.remove		= xen_drm_drv_remove,
+	.driver		= {
+		.name	= XENDISPL_DRIVER_NAME,
+	},
+};
+
+static void xen_drm_drv_deinit(struct xen_drm_front_info *front_info)
+{
+	if (!front_info->drm_pdrv_registered)
+		return;
+
+	if (front_info->drm_pdev)
+		platform_device_unregister(front_info->drm_pdev);
+
+	platform_driver_unregister(&xen_drm_front_front_info);
+	front_info->drm_pdrv_registered = false;
+	front_info->drm_pdev = NULL;
+}
+
+static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
+{
+	int ret;
+
+	ret = platform_driver_register(&xen_drm_front_front_info);
+	if (ret < 0)
+		return ret;
+
+	front_info->drm_pdrv_registered = true;
+	/* pass card configuration via platform data */
+	xen_drm_front_platform_info.data = &front_info->cfg;
+	xen_drm_front_platform_info.size_data = sizeof(front_info->cfg);
+
+	front_info->drm_pdev = platform_device_register_full(
+			&xen_drm_front_platform_info);
+	if (IS_ERR_OR_NULL(front_info->drm_pdev)) {
+		DRM_ERROR("Failed to register " XENDISPL_DRIVER_NAME " PV DRM driver\n");
+		front_info->drm_pdev = NULL;
+		xen_drm_drv_deinit(front_info);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 {
+	xen_drm_drv_deinit(front_info);
 	xen_drm_front_evtchnl_free_all(front_info);
 }
 
@@ -59,13 +207,27 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
 static int backend_on_connected(struct xen_drm_front_info *front_info)
 {
 	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
-	return 0;
+	return xen_drm_drv_init(front_info);
 }
 
 static void backend_on_disconnected(struct xen_drm_front_info *front_info)
 {
+	bool removed = true;
+
+	if (front_info->drm_pdev) {
+		if (xen_drm_front_drv_is_used(front_info->drm_pdev)) {
+			DRM_WARN("DRM driver still in use, deferring removal\n");
+			removed = false;
+		} else
+			xen_drv_remove_internal(front_info);
+	}
+
 	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
-	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+
+	if (removed)
+		xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+	else
+		xenbus_switch_state(front_info->xb_dev, XenbusStateReconfiguring);
 }
 
 static void backend_on_changed(struct xenbus_device *xb_dev,
@@ -148,6 +310,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 
 	front_info->xb_dev = xb_dev;
 	spin_lock_init(&front_info->io_lock);
+	front_info->drm_pdrv_registered = false;
 	dev_set_drvdata(&xb_dev->dev, front_info);
 	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
 #include "xen_drm_front_cfg.h"
 
 #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
 #define GRANT_INVALID_REF	0
 #endif
 
+struct xen_drm_front_drm_pipeline;
+
 struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
 	/* CAUTION! this is called with a spin_lock held! */
 	void (*on_frame_done)(struct platform_device *pdev,
 			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
 };
 
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
 	/* to protect data between backend IO code and interrupt handler */
 	spinlock_t io_lock;
+	bool drm_pdrv_registered;
 	/* virtual DRM platform device */
 	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0
new file mode 100644
index 000000000000..b3764d5ed0f6
@@ -0,0 +1,211 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+#include "xen_drm_front_drv.h"
+
+static int dumb_create(struct drm_file *filp,
+		struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+	return -EINVAL;
+}
+
+static void free_object(struct drm_gem_object *obj)
+{
+	struct xen_drm_front_drm_info *drm_info = obj->dev->dev_private;
+
+	drm_info->front_ops->dbuf_destroy(drm_info->front_info,
+			xen_drm_front_dbuf_to_cookie(obj));
+}
+
+static void on_frame_done(struct platform_device *pdev,
+		int conn_idx, uint64_t fb_cookie)
+{
+}
+
+static void lastclose(struct drm_device *dev)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+
+	drm_info->front_ops->drm_last_close(drm_info->front_info);
+}
+
+static int gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static struct sg_table *prime_get_sg_table(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static struct drm_gem_object *prime_import_sg_table(struct drm_device *dev,
+		struct dma_buf_attachment *attach, struct sg_table *sgt)
+{
+	return NULL;
+}
+
+static void *prime_vmap(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static void prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+}
+
+static int prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static const struct file_operations xendrm_fops = {
+	.owner          = THIS_MODULE,
+	.open           = drm_open,
+	.release        = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = drm_compat_ioctl,
+#endif
+	.poll           = drm_poll,
+	.read           = drm_read,
+	.llseek         = no_llseek,
+	.mmap           = gem_mmap,
+};
+
+static const struct vm_operations_struct xen_drm_vm_ops = {
+	.open           = drm_gem_vm_open,
+	.close          = drm_gem_vm_close,
+};
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",
+	.major                     = 1,
+	.minor                     = 0,
+};
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops)
+{
+	struct xen_drm_front_cfg *cfg = dev_get_platdata(&pdev->dev);
+	struct xen_drm_front_drm_info *drm_info;
+	struct drm_device *dev;
+	int ret;
+
+	DRM_INFO("Creating %s\n", xen_drm_driver.desc);
+
+	drm_info = devm_kzalloc(&pdev->dev, sizeof(*drm_info), GFP_KERNEL);
+	if (!drm_info)
+		return -ENOMEM;
+
+	drm_info->front_ops = front_ops;
+	drm_info->front_ops->on_frame_done = on_frame_done;
+	drm_info->front_info = cfg->front_info;
+
+	dev = drm_dev_alloc(&xen_drm_driver, &pdev->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	drm_info->drm_dev = dev;
+
+	drm_info->cfg = cfg;
+	dev->dev_private = drm_info;
+	platform_set_drvdata(pdev, drm_info);
+
+	ret = drm_vblank_init(dev, cfg->num_connectors);
+	if (ret) {
+		DRM_ERROR("Failed to initialize vblank, ret %d\n", ret);
+		return ret;
+	}
+
+	dev->irq_enabled = 1;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		goto fail_register;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+			xen_drm_driver.name, xen_drm_driver.major,
+			xen_drm_driver.minor, xen_drm_driver.patchlevel,
+			xen_drm_driver.date, dev->primary->index);
+
+	return 0;
+
+fail_register:
+	drm_dev_unregister(dev);
+	drm_mode_config_cleanup(dev);
+	return ret;
+}
+
+int xen_drm_front_drv_remove(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev = drm_info->drm_dev;
+
+	if (dev) {
+		drm_dev_unregister(dev);
+		drm_atomic_helper_shutdown(dev);
+		drm_mode_config_cleanup(dev);
+		drm_dev_unref(dev);
+	}
+	return 0;
+}
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;
+}
drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0
new file mode 100644
index 000000000000..aaa476535c13
@@ -0,0 +1,60 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_DRV_H_
+#define __XEN_DRM_FRONT_DRV_H_
+
+#include <drm/drmP.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+
+struct xen_drm_front_drm_pipeline {
+	struct xen_drm_front_drm_info *drm_info;
+
+	int index;
+};
+
+struct xen_drm_front_drm_info {
+	struct xen_drm_front_info *front_info;
+	struct xen_drm_front_ops *front_ops;
+	struct drm_device *drm_dev;
+	struct xen_drm_front_cfg *cfg;
+};
+
+static inline uint64_t xen_drm_front_fb_to_cookie(
+		struct drm_framebuffer *fb)
+{
+	return (uint64_t)fb;
+}
+
+static inline uint64_t xen_drm_front_dbuf_to_cookie(
+		struct drm_gem_object *gem_obj)
+{
+	return (uint64_t)gem_obj;
+}
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops);
+
+int xen_drm_front_drv_remove(struct platform_device *pdev);
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev);
+
+#endif /* __XEN_DRM_FRONT_DRV_H_ */
+
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#51 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

Quoted 128 lines · Daniel Vetter
Quoted 127 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
  drivers/gpu/drm/xen/Makefile            |   1 +
  drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
  drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
  drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
  drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
  5 files changed, 462 insertions(+), 3 deletions(-)

create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h

drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
  # SPDX-License-Identifier: GPL-2.0
 
  drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
  		      xen_drm_front_evtchnl.o \
  		      xen_drm_front_shbuf.o \
  		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +73 -1
index 0d94ff272da3..8de88e359d5e 100644
@@ -18,6 +18,8 @@
 
  #include <drm/drmP.h>
 
+#include <linux/of_device.h>
+
  #include <xen/platform_pci.h>
  #include <xen/xen.h>
  #include <xen/xenbus.h>
@@ -25,15 +27,161 @@
  #include <xen/interface/io/displif.h>
 
  #include "xen_drm_front.h"
+#include "xen_drm_front_drv.h"
  #include "xen_drm_front_evtchnl.h"
  #include "xen_drm_front_shbuf.h"
 
+static int be_mode_set(struct xen_drm_front_drm_pipeline *pipeline, uint32_t x,
+		uint32_t y, uint32_t width, uint32_t height, uint32_t bpp,
+		uint64_t fb_cookie)
+
+{
+	return 0;
+}
+
+static int be_dbuf_create_int(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages,
+		struct sg_table *sgt)
+{
+	return 0;
+}
+
+static int be_dbuf_create_from_sgt(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct sg_table *sgt)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, NULL, sgt);
+}
+
+static int be_dbuf_create_from_pages(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, pages, NULL);
+}
+
+static int be_dbuf_destroy(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie)
+{
+	return 0;
+}
+
+static int be_fb_attach(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint64_t fb_cookie, uint32_t width,
+		uint32_t height, uint32_t pixel_format)
+{
+	return 0;
+}
+
+static int be_fb_detach(struct xen_drm_front_info *front_info,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static int be_page_flip(struct xen_drm_front_info *front_info, int conn_idx,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static void xen_drm_drv_unload(struct xen_drm_front_info *front_info)
+{
+	if (front_info->xb_dev->state != XenbusStateReconfiguring)
+		return;
+
+	DRM_DEBUG("Can try removing driver now\n");
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
  static struct xen_drm_front_ops front_ops = {
-	/* placeholder for now */
+	.mode_set = be_mode_set,
+	.dbuf_create_from_pages = be_dbuf_create_from_pages,
+	.dbuf_create_from_sgt = be_dbuf_create_from_sgt,
+	.dbuf_destroy = be_dbuf_destroy,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front.c line 109

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front.c +5 -0
+	.fb_attach = be_fb_attach,
+	.fb_detach = be_fb_detach,
+	.page_flip = be_page_flip,
+	.drm_last_close = xen_drm_drv_unload,
+};

This looks like a midlayer/DRM-abstraction in your driver. Please remove, and instead directly hook your xen-front code into the relevant drm callbacks.

ok, will do

Quoted 4 lines

In general also pls make sure you don't implement dummy callbacks that do nothing, we've tried really hard to make them all optional in the drm infrastructure.

sure

Quoted 456 lines

-Daniel

Quoted 454 lines
drivers/gpu/drm/xen/xen_drm_front.c +88 -2
+
+static int xen_drm_drv_probe(struct platform_device *pdev)
+{
+	/*
+	 * The device is not spawn from a device tree, so arch_setup_dma_ops
+	 * is not called, thus leaving the device with dummy DMA ops.
+	 * This makes the device return error on PRIME buffer import, which
+	 * is not correct: to fix this call of_dma_configure() with a NULL
+	 * node to set default DMA ops.
+	 */
+	of_dma_configure(&pdev->dev, NULL);
+	return xen_drm_front_drv_probe(pdev, &front_ops);
+}
+
+static int xen_drm_drv_remove(struct platform_device *pdev)
+{
+	return xen_drm_front_drv_remove(pdev);
+}
+
+struct platform_device_info xen_drm_front_platform_info = {
+	.name = XENDISPL_DRIVER_NAME,
+	.id = 0,
+	.num_res = 0,
+	.dma_mask = DMA_BIT_MASK(32),
  };
 
+static struct platform_driver xen_drm_front_front_info = {
+	.probe		= xen_drm_drv_probe,
+	.remove		= xen_drm_drv_remove,
+	.driver		= {
+		.name	= XENDISPL_DRIVER_NAME,
+	},
+};
+
+static void xen_drm_drv_deinit(struct xen_drm_front_info *front_info)
+{
+	if (!front_info->drm_pdrv_registered)
+		return;
+
+	if (front_info->drm_pdev)
+		platform_device_unregister(front_info->drm_pdev);
+
+	platform_driver_unregister(&xen_drm_front_front_info);
+	front_info->drm_pdrv_registered = false;
+	front_info->drm_pdev = NULL;
+}
+
+static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
+{
+	int ret;
+
+	ret = platform_driver_register(&xen_drm_front_front_info);
+	if (ret < 0)
+		return ret;
+
+	front_info->drm_pdrv_registered = true;
+	/* pass card configuration via platform data */
+	xen_drm_front_platform_info.data = &front_info->cfg;
+	xen_drm_front_platform_info.size_data = sizeof(front_info->cfg);
+
+	front_info->drm_pdev = platform_device_register_full(
+			&xen_drm_front_platform_info);
+	if (IS_ERR_OR_NULL(front_info->drm_pdev)) {
+		DRM_ERROR("Failed to register " XENDISPL_DRIVER_NAME " PV DRM driver\n");
+		front_info->drm_pdev = NULL;
+		xen_drm_drv_deinit(front_info);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
  static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
  {
+	xen_drm_drv_deinit(front_info);
  	xen_drm_front_evtchnl_free_all(front_info);
  }
 
@@ -59,13 +207,27 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
  static int backend_on_connected(struct xen_drm_front_info *front_info)
  {
  	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
-	return 0;
+	return xen_drm_drv_init(front_info);
  }
 
  static void backend_on_disconnected(struct xen_drm_front_info *front_info)
  {
+	bool removed = true;
+
+	if (front_info->drm_pdev) {
+		if (xen_drm_front_drv_is_used(front_info->drm_pdev)) {
+			DRM_WARN("DRM driver still in use, deferring removal\n");
+			removed = false;
+		} else
+			xen_drv_remove_internal(front_info);
+	}
+
  	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
-	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+
+	if (removed)
+		xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+	else
+		xenbus_switch_state(front_info->xb_dev, XenbusStateReconfiguring);
  }
 
  static void backend_on_changed(struct xenbus_device *xb_dev,
@@ -148,6 +310,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 
  	front_info->xb_dev = xb_dev;
  	spin_lock_init(&front_info->io_lock);
+	front_info->drm_pdrv_registered = false;
  	dev_set_drvdata(&xb_dev->dev, front_info);
  	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
  }
drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
  #ifndef __XEN_DRM_FRONT_H_
  #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
  #include "xen_drm_front_cfg.h"
 
  #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
  #define GRANT_INVALID_REF	0
  #endif
 
+struct xen_drm_front_drm_pipeline;
+
  struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
  	/* CAUTION! this is called with a spin_lock held! */
  	void (*on_frame_done)(struct platform_device *pdev,
  			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
  };
 
  struct xen_drm_front_info {
  	struct xenbus_device *xb_dev;
  	/* to protect data between backend IO code and interrupt handler */
  	spinlock_t io_lock;
+	bool drm_pdrv_registered;
  	/* virtual DRM platform device */
  	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0
new file mode 100644
index 000000000000..b3764d5ed0f6
@@ -0,0 +1,211 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+#include "xen_drm_front_drv.h"
+
+static int dumb_create(struct drm_file *filp,
+		struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+	return -EINVAL;
+}
+
+static void free_object(struct drm_gem_object *obj)
+{
+	struct xen_drm_front_drm_info *drm_info = obj->dev->dev_private;
+
+	drm_info->front_ops->dbuf_destroy(drm_info->front_info,
+			xen_drm_front_dbuf_to_cookie(obj));
+}
+
+static void on_frame_done(struct platform_device *pdev,
+		int conn_idx, uint64_t fb_cookie)
+{
+}
+
+static void lastclose(struct drm_device *dev)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+
+	drm_info->front_ops->drm_last_close(drm_info->front_info);
+}
+
+static int gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static struct sg_table *prime_get_sg_table(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static struct drm_gem_object *prime_import_sg_table(struct drm_device *dev,
+		struct dma_buf_attachment *attach, struct sg_table *sgt)
+{
+	return NULL;
+}
+
+static void *prime_vmap(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static void prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+}
+
+static int prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static const struct file_operations xendrm_fops = {
+	.owner          = THIS_MODULE,
+	.open           = drm_open,
+	.release        = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = drm_compat_ioctl,
+#endif
+	.poll           = drm_poll,
+	.read           = drm_read,
+	.llseek         = no_llseek,
+	.mmap           = gem_mmap,
+};
+
+static const struct vm_operations_struct xen_drm_vm_ops = {
+	.open           = drm_gem_vm_open,
+	.close          = drm_gem_vm_close,
+};
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",
+	.major                     = 1,
+	.minor                     = 0,
+};
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops)
+{
+	struct xen_drm_front_cfg *cfg = dev_get_platdata(&pdev->dev);
+	struct xen_drm_front_drm_info *drm_info;
+	struct drm_device *dev;
+	int ret;
+
+	DRM_INFO("Creating %s\n", xen_drm_driver.desc);
+
+	drm_info = devm_kzalloc(&pdev->dev, sizeof(*drm_info), GFP_KERNEL);
+	if (!drm_info)
+		return -ENOMEM;
+
+	drm_info->front_ops = front_ops;
+	drm_info->front_ops->on_frame_done = on_frame_done;
+	drm_info->front_info = cfg->front_info;
+
+	dev = drm_dev_alloc(&xen_drm_driver, &pdev->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	drm_info->drm_dev = dev;
+
+	drm_info->cfg = cfg;
+	dev->dev_private = drm_info;
+	platform_set_drvdata(pdev, drm_info);
+
+	ret = drm_vblank_init(dev, cfg->num_connectors);
+	if (ret) {
+		DRM_ERROR("Failed to initialize vblank, ret %d\n", ret);
+		return ret;
+	}
+
+	dev->irq_enabled = 1;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		goto fail_register;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+			xen_drm_driver.name, xen_drm_driver.major,
+			xen_drm_driver.minor, xen_drm_driver.patchlevel,
+			xen_drm_driver.date, dev->primary->index);
+
+	return 0;
+
+fail_register:
+	drm_dev_unregister(dev);
+	drm_mode_config_cleanup(dev);
+	return ret;
+}
+
+int xen_drm_front_drv_remove(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev = drm_info->drm_dev;
+
+	if (dev) {
+		drm_dev_unregister(dev);
+		drm_atomic_helper_shutdown(dev);
+		drm_mode_config_cleanup(dev);
+		drm_dev_unref(dev);
+	}
+	return 0;
+}
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;
+}
drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0
new file mode 100644
index 000000000000..aaa476535c13
@@ -0,0 +1,60 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_DRV_H_
+#define __XEN_DRM_FRONT_DRV_H_
+
+#include <drm/drmP.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+
+struct xen_drm_front_drm_pipeline {
+	struct xen_drm_front_drm_info *drm_info;
+
+	int index;
+};
+
+struct xen_drm_front_drm_info {
+	struct xen_drm_front_info *front_info;
+	struct xen_drm_front_ops *front_ops;
+	struct drm_device *drm_dev;
+	struct xen_drm_front_cfg *cfg;
+};
+
+static inline uint64_t xen_drm_front_fb_to_cookie(
+		struct drm_framebuffer *fb)
+{
+	return (uint64_t)fb;
+}
+
+static inline uint64_t xen_drm_front_dbuf_to_cookie(
+		struct drm_gem_object *gem_obj)
+{
+	return (uint64_t)gem_obj;
+}
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops);
+
+int xen_drm_front_drv_remove(struct platform_device *pdev);
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev);
+
+#endif /* __XEN_DRM_FRONT_DRV_H_ */
+
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#52 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Daniel Vetter
Quoted 128 lines · Daniel Vetter
Quoted 127 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
  drivers/gpu/drm/xen/Makefile            |   1 +
  drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
  drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
  drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
  drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
  5 files changed, 462 insertions(+), 3 deletions(-)

create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h

drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
  # SPDX-License-Identifier: GPL-2.0
 
  drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
  		      xen_drm_front_evtchnl.o \
  		      xen_drm_front_shbuf.o \
  		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +73 -1
index 0d94ff272da3..8de88e359d5e 100644
@@ -18,6 +18,8 @@
 
  #include <drm/drmP.h>
 
+#include <linux/of_device.h>
+
  #include <xen/platform_pci.h>
  #include <xen/xen.h>
  #include <xen/xenbus.h>
@@ -25,15 +27,161 @@
  #include <xen/interface/io/displif.h>
 
  #include "xen_drm_front.h"
+#include "xen_drm_front_drv.h"
  #include "xen_drm_front_evtchnl.h"
  #include "xen_drm_front_shbuf.h"
 
+static int be_mode_set(struct xen_drm_front_drm_pipeline *pipeline, uint32_t x,
+		uint32_t y, uint32_t width, uint32_t height, uint32_t bpp,
+		uint64_t fb_cookie)
+
+{
+	return 0;
+}
+
+static int be_dbuf_create_int(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages,
+		struct sg_table *sgt)
+{
+	return 0;
+}
+
+static int be_dbuf_create_from_sgt(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct sg_table *sgt)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, NULL, sgt);
+}
+
+static int be_dbuf_create_from_pages(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, pages, NULL);
+}
+
+static int be_dbuf_destroy(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie)
+{
+	return 0;
+}
+
+static int be_fb_attach(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint64_t fb_cookie, uint32_t width,
+		uint32_t height, uint32_t pixel_format)
+{
+	return 0;
+}
+
+static int be_fb_detach(struct xen_drm_front_info *front_info,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static int be_page_flip(struct xen_drm_front_info *front_info, int conn_idx,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static void xen_drm_drv_unload(struct xen_drm_front_info *front_info)
+{
+	if (front_info->xb_dev->state != XenbusStateReconfiguring)
+		return;
+
+	DRM_DEBUG("Can try removing driver now\n");
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
  static struct xen_drm_front_ops front_ops = {
-	/* placeholder for now */
+	.mode_set = be_mode_set,
+	.dbuf_create_from_pages = be_dbuf_create_from_pages,
+	.dbuf_create_from_sgt = be_dbuf_create_from_sgt,
+	.dbuf_destroy = be_dbuf_destroy,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front.c line 109

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front.c +5 -0
+	.fb_attach = be_fb_attach,
+	.fb_detach = be_fb_detach,
+	.page_flip = be_page_flip,
+	.drm_last_close = xen_drm_drv_unload,
+};

This looks like a midlayer/DRM-abstraction in your driver. Please remove, and instead directly hook your xen-front code into the relevant drm callbacks.

ok, will do

Quoted 4 lines

In general also pls make sure you don't implement dummy callbacks that do nothing, we've tried really hard to make them all optional in the drm infrastructure.

sure

Quoted 456 lines

-Daniel

Quoted 454 lines
drivers/gpu/drm/xen/xen_drm_front.c +88 -2
+
+static int xen_drm_drv_probe(struct platform_device *pdev)
+{
+	/*
+	 * The device is not spawn from a device tree, so arch_setup_dma_ops
+	 * is not called, thus leaving the device with dummy DMA ops.
+	 * This makes the device return error on PRIME buffer import, which
+	 * is not correct: to fix this call of_dma_configure() with a NULL
+	 * node to set default DMA ops.
+	 */
+	of_dma_configure(&pdev->dev, NULL);
+	return xen_drm_front_drv_probe(pdev, &front_ops);
+}
+
+static int xen_drm_drv_remove(struct platform_device *pdev)
+{
+	return xen_drm_front_drv_remove(pdev);
+}
+
+struct platform_device_info xen_drm_front_platform_info = {
+	.name = XENDISPL_DRIVER_NAME,
+	.id = 0,
+	.num_res = 0,
+	.dma_mask = DMA_BIT_MASK(32),
  };
 
+static struct platform_driver xen_drm_front_front_info = {
+	.probe		= xen_drm_drv_probe,
+	.remove		= xen_drm_drv_remove,
+	.driver		= {
+		.name	= XENDISPL_DRIVER_NAME,
+	},
+};
+
+static void xen_drm_drv_deinit(struct xen_drm_front_info *front_info)
+{
+	if (!front_info->drm_pdrv_registered)
+		return;
+
+	if (front_info->drm_pdev)
+		platform_device_unregister(front_info->drm_pdev);
+
+	platform_driver_unregister(&xen_drm_front_front_info);
+	front_info->drm_pdrv_registered = false;
+	front_info->drm_pdev = NULL;
+}
+
+static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
+{
+	int ret;
+
+	ret = platform_driver_register(&xen_drm_front_front_info);
+	if (ret < 0)
+		return ret;
+
+	front_info->drm_pdrv_registered = true;
+	/* pass card configuration via platform data */
+	xen_drm_front_platform_info.data = &front_info->cfg;
+	xen_drm_front_platform_info.size_data = sizeof(front_info->cfg);
+
+	front_info->drm_pdev = platform_device_register_full(
+			&xen_drm_front_platform_info);
+	if (IS_ERR_OR_NULL(front_info->drm_pdev)) {
+		DRM_ERROR("Failed to register " XENDISPL_DRIVER_NAME " PV DRM driver\n");
+		front_info->drm_pdev = NULL;
+		xen_drm_drv_deinit(front_info);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
  static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
  {
+	xen_drm_drv_deinit(front_info);
  	xen_drm_front_evtchnl_free_all(front_info);
  }
 
@@ -59,13 +207,27 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
  static int backend_on_connected(struct xen_drm_front_info *front_info)
  {
  	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
-	return 0;
+	return xen_drm_drv_init(front_info);
  }
 
  static void backend_on_disconnected(struct xen_drm_front_info *front_info)
  {
+	bool removed = true;
+
+	if (front_info->drm_pdev) {
+		if (xen_drm_front_drv_is_used(front_info->drm_pdev)) {
+			DRM_WARN("DRM driver still in use, deferring removal\n");
+			removed = false;
+		} else
+			xen_drv_remove_internal(front_info);
+	}
+
  	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
-	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+
+	if (removed)
+		xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+	else
+		xenbus_switch_state(front_info->xb_dev, XenbusStateReconfiguring);
  }
 
  static void backend_on_changed(struct xenbus_device *xb_dev,
@@ -148,6 +310,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 
  	front_info->xb_dev = xb_dev;
  	spin_lock_init(&front_info->io_lock);
+	front_info->drm_pdrv_registered = false;
  	dev_set_drvdata(&xb_dev->dev, front_info);
  	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
  }
drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
  #ifndef __XEN_DRM_FRONT_H_
  #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
  #include "xen_drm_front_cfg.h"
 
  #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
  #define GRANT_INVALID_REF	0
  #endif
 
+struct xen_drm_front_drm_pipeline;
+
  struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
  	/* CAUTION! this is called with a spin_lock held! */
  	void (*on_frame_done)(struct platform_device *pdev,
  			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
  };
 
  struct xen_drm_front_info {
  	struct xenbus_device *xb_dev;
  	/* to protect data between backend IO code and interrupt handler */
  	spinlock_t io_lock;
+	bool drm_pdrv_registered;
  	/* virtual DRM platform device */
  	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0
new file mode 100644
index 000000000000..b3764d5ed0f6
@@ -0,0 +1,211 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+#include "xen_drm_front_drv.h"
+
+static int dumb_create(struct drm_file *filp,
+		struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+	return -EINVAL;
+}
+
+static void free_object(struct drm_gem_object *obj)
+{
+	struct xen_drm_front_drm_info *drm_info = obj->dev->dev_private;
+
+	drm_info->front_ops->dbuf_destroy(drm_info->front_info,
+			xen_drm_front_dbuf_to_cookie(obj));
+}
+
+static void on_frame_done(struct platform_device *pdev,
+		int conn_idx, uint64_t fb_cookie)
+{
+}
+
+static void lastclose(struct drm_device *dev)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+
+	drm_info->front_ops->drm_last_close(drm_info->front_info);
+}
+
+static int gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static struct sg_table *prime_get_sg_table(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static struct drm_gem_object *prime_import_sg_table(struct drm_device *dev,
+		struct dma_buf_attachment *attach, struct sg_table *sgt)
+{
+	return NULL;
+}
+
+static void *prime_vmap(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static void prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+}
+
+static int prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static const struct file_operations xendrm_fops = {
+	.owner          = THIS_MODULE,
+	.open           = drm_open,
+	.release        = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = drm_compat_ioctl,
+#endif
+	.poll           = drm_poll,
+	.read           = drm_read,
+	.llseek         = no_llseek,
+	.mmap           = gem_mmap,
+};
+
+static const struct vm_operations_struct xen_drm_vm_ops = {
+	.open           = drm_gem_vm_open,
+	.close          = drm_gem_vm_close,
+};
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",
+	.major                     = 1,
+	.minor                     = 0,
+};
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops)
+{
+	struct xen_drm_front_cfg *cfg = dev_get_platdata(&pdev->dev);
+	struct xen_drm_front_drm_info *drm_info;
+	struct drm_device *dev;
+	int ret;
+
+	DRM_INFO("Creating %s\n", xen_drm_driver.desc);
+
+	drm_info = devm_kzalloc(&pdev->dev, sizeof(*drm_info), GFP_KERNEL);
+	if (!drm_info)
+		return -ENOMEM;
+
+	drm_info->front_ops = front_ops;
+	drm_info->front_ops->on_frame_done = on_frame_done;
+	drm_info->front_info = cfg->front_info;
+
+	dev = drm_dev_alloc(&xen_drm_driver, &pdev->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	drm_info->drm_dev = dev;
+
+	drm_info->cfg = cfg;
+	dev->dev_private = drm_info;
+	platform_set_drvdata(pdev, drm_info);
+
+	ret = drm_vblank_init(dev, cfg->num_connectors);
+	if (ret) {
+		DRM_ERROR("Failed to initialize vblank, ret %d\n", ret);
+		return ret;
+	}
+
+	dev->irq_enabled = 1;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		goto fail_register;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+			xen_drm_driver.name, xen_drm_driver.major,
+			xen_drm_driver.minor, xen_drm_driver.patchlevel,
+			xen_drm_driver.date, dev->primary->index);
+
+	return 0;
+
+fail_register:
+	drm_dev_unregister(dev);
+	drm_mode_config_cleanup(dev);
+	return ret;
+}
+
+int xen_drm_front_drv_remove(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev = drm_info->drm_dev;
+
+	if (dev) {
+		drm_dev_unregister(dev);
+		drm_atomic_helper_shutdown(dev);
+		drm_mode_config_cleanup(dev);
+		drm_dev_unref(dev);
+	}
+	return 0;
+}
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;
+}
drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0
new file mode 100644
index 000000000000..aaa476535c13
@@ -0,0 +1,60 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_DRV_H_
+#define __XEN_DRM_FRONT_DRV_H_
+
+#include <drm/drmP.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+
+struct xen_drm_front_drm_pipeline {
+	struct xen_drm_front_drm_info *drm_info;
+
+	int index;
+};
+
+struct xen_drm_front_drm_info {
+	struct xen_drm_front_info *front_info;
+	struct xen_drm_front_ops *front_ops;
+	struct drm_device *drm_dev;
+	struct xen_drm_front_cfg *cfg;
+};
+
+static inline uint64_t xen_drm_front_fb_to_cookie(
+		struct drm_framebuffer *fb)
+{
+	return (uint64_t)fb;
+}
+
+static inline uint64_t xen_drm_front_dbuf_to_cookie(
+		struct drm_gem_object *gem_obj)
+{
+	return (uint64_t)gem_obj;
+}
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops);
+
+int xen_drm_front_drv_remove(struct platform_device *pdev);
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev);
+
+#endif /* __XEN_DRM_FRONT_DRV_H_ */
+
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#53 lore raw

Re: [PATCH 6/9] drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Oleksandr Andrushchenko
Quoted 122 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
 drivers/gpu/drm/xen/Makefile            |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
 5 files changed, 462 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h
drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
 		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +69 -0
index 0d94ff272da3..8de88e359d5e 100644
@@ -18,6 +18,8 @@
 
 #include <drm/drmP.h>
 
+#include <linux/of_device.h>
+
 #include <xen/platform_pci.h>
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -25,15 +27,161 @@
 #include <xen/interface/io/displif.h>
 
 #include "xen_drm_front.h"
+#include "xen_drm_front_drv.h"
 #include "xen_drm_front_evtchnl.h"
 #include "xen_drm_front_shbuf.h"
 
+static int be_mode_set(struct xen_drm_front_drm_pipeline *pipeline, uint32_t x,
+		uint32_t y, uint32_t width, uint32_t height, uint32_t bpp,
+		uint64_t fb_cookie)
+
+{
+	return 0;
+}
+
+static int be_dbuf_create_int(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages,
+		struct sg_table *sgt)
+{
+	return 0;
+}
+
+static int be_dbuf_create_from_sgt(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct sg_table *sgt)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, NULL, sgt);
+}
+
+static int be_dbuf_create_from_pages(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+		uint32_t bpp, uint64_t size, struct page **pages)
+{
+	return be_dbuf_create_int(front_info, dbuf_cookie, width, height,
+			bpp, size, pages, NULL);
+}
+
+static int be_dbuf_destroy(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie)
+{
+	return 0;
+}
+
+static int be_fb_attach(struct xen_drm_front_info *front_info,
+		uint64_t dbuf_cookie, uint64_t fb_cookie, uint32_t width,
+		uint32_t height, uint32_t pixel_format)
+{
+	return 0;
+}
+
+static int be_fb_detach(struct xen_drm_front_info *front_info,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static int be_page_flip(struct xen_drm_front_info *front_info, int conn_idx,
+		uint64_t fb_cookie)
+{
+	return 0;
+}
+
+static void xen_drm_drv_unload(struct xen_drm_front_info *front_info)
+{
+	if (front_info->xb_dev->state != XenbusStateReconfiguring)
+		return;
+
+	DRM_DEBUG("Can try removing driver now\n");
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static struct xen_drm_front_ops front_ops = {

drivers/gpu/drm/xen/xen_drm_front.c line 109

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front.c +9 -1
-	/* placeholder for now */
+	.mode_set = be_mode_set,
+	.dbuf_create_from_pages = be_dbuf_create_from_pages,
+	.dbuf_create_from_sgt = be_dbuf_create_from_sgt,
+	.dbuf_destroy = be_dbuf_destroy,
+	.fb_attach = be_fb_attach,
+	.fb_detach = be_fb_detach,
+	.page_flip = be_page_flip,
+	.drm_last_close = xen_drm_drv_unload,
+};

This looks like a midlayer/DRM-abstraction in your driver. Please remove, and instead directly hook your xen-front code into the relevant drm callbacks.

In general also pls make sure you don't implement dummy callbacks that do nothing, we've tried really hard to make them all optional in the drm infrastructure.
-Daniel

Quoted 458 lines
drivers/gpu/drm/xen/xen_drm_front.c +88 -2
+
+static int xen_drm_drv_probe(struct platform_device *pdev)
+{
+	/*
+	 * The device is not spawn from a device tree, so arch_setup_dma_ops
+	 * is not called, thus leaving the device with dummy DMA ops.
+	 * This makes the device return error on PRIME buffer import, which
+	 * is not correct: to fix this call of_dma_configure() with a NULL
+	 * node to set default DMA ops.
+	 */
+	of_dma_configure(&pdev->dev, NULL);
+	return xen_drm_front_drv_probe(pdev, &front_ops);
+}
+
+static int xen_drm_drv_remove(struct platform_device *pdev)
+{
+	return xen_drm_front_drv_remove(pdev);
+}
+
+struct platform_device_info xen_drm_front_platform_info = {
+	.name = XENDISPL_DRIVER_NAME,
+	.id = 0,
+	.num_res = 0,
+	.dma_mask = DMA_BIT_MASK(32),
 };
 
+static struct platform_driver xen_drm_front_front_info = {
+	.probe		= xen_drm_drv_probe,
+	.remove		= xen_drm_drv_remove,
+	.driver		= {
+		.name	= XENDISPL_DRIVER_NAME,
+	},
+};
+
+static void xen_drm_drv_deinit(struct xen_drm_front_info *front_info)
+{
+	if (!front_info->drm_pdrv_registered)
+		return;
+
+	if (front_info->drm_pdev)
+		platform_device_unregister(front_info->drm_pdev);
+
+	platform_driver_unregister(&xen_drm_front_front_info);
+	front_info->drm_pdrv_registered = false;
+	front_info->drm_pdev = NULL;
+}
+
+static int xen_drm_drv_init(struct xen_drm_front_info *front_info)
+{
+	int ret;
+
+	ret = platform_driver_register(&xen_drm_front_front_info);
+	if (ret < 0)
+		return ret;
+
+	front_info->drm_pdrv_registered = true;
+	/* pass card configuration via platform data */
+	xen_drm_front_platform_info.data = &front_info->cfg;
+	xen_drm_front_platform_info.size_data = sizeof(front_info->cfg);
+
+	front_info->drm_pdev = platform_device_register_full(
+			&xen_drm_front_platform_info);
+	if (IS_ERR_OR_NULL(front_info->drm_pdev)) {
+		DRM_ERROR("Failed to register " XENDISPL_DRIVER_NAME " PV DRM driver\n");
+		front_info->drm_pdev = NULL;
+		xen_drm_drv_deinit(front_info);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
 {
+	xen_drm_drv_deinit(front_info);
 	xen_drm_front_evtchnl_free_all(front_info);
 }
 
@@ -59,13 +207,27 @@ static int backend_on_initwait(struct xen_drm_front_info *front_info)
 static int backend_on_connected(struct xen_drm_front_info *front_info)
 {
 	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_CONNECTED);
-	return 0;
+	return xen_drm_drv_init(front_info);
 }
 
 static void backend_on_disconnected(struct xen_drm_front_info *front_info)
 {
+	bool removed = true;
+
+	if (front_info->drm_pdev) {
+		if (xen_drm_front_drv_is_used(front_info->drm_pdev)) {
+			DRM_WARN("DRM driver still in use, deferring removal\n");
+			removed = false;
+		} else
+			xen_drv_remove_internal(front_info);
+	}
+
 	xen_drm_front_evtchnl_set_state(front_info, EVTCHNL_STATE_DISCONNECTED);
-	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+
+	if (removed)
+		xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+	else
+		xenbus_switch_state(front_info->xb_dev, XenbusStateReconfiguring);
 }
 
 static void backend_on_changed(struct xenbus_device *xb_dev,
@@ -148,6 +310,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
 
 	front_info->xb_dev = xb_dev;
 	spin_lock_init(&front_info->io_lock);
+	front_info->drm_pdrv_registered = false;
 	dev_set_drvdata(&xb_dev->dev, front_info);
 	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
 #include "xen_drm_front_cfg.h"
 
 #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
 #define GRANT_INVALID_REF	0
 #endif
 
+struct xen_drm_front_drm_pipeline;
+
 struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
 	/* CAUTION! this is called with a spin_lock held! */
 	void (*on_frame_done)(struct platform_device *pdev,
 			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
 };
 
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
 	/* to protect data between backend IO code and interrupt handler */
 	spinlock_t io_lock;
+	bool drm_pdrv_registered;
 	/* virtual DRM platform device */
 	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0
new file mode 100644
index 000000000000..b3764d5ed0f6
@@ -0,0 +1,211 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+#include "xen_drm_front_drv.h"
+
+static int dumb_create(struct drm_file *filp,
+		struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+	return -EINVAL;
+}
+
+static void free_object(struct drm_gem_object *obj)
+{
+	struct xen_drm_front_drm_info *drm_info = obj->dev->dev_private;
+
+	drm_info->front_ops->dbuf_destroy(drm_info->front_info,
+			xen_drm_front_dbuf_to_cookie(obj));
+}
+
+static void on_frame_done(struct platform_device *pdev,
+		int conn_idx, uint64_t fb_cookie)
+{
+}
+
+static void lastclose(struct drm_device *dev)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+
+	drm_info->front_ops->drm_last_close(drm_info->front_info);
+}
+
+static int gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static struct sg_table *prime_get_sg_table(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static struct drm_gem_object *prime_import_sg_table(struct drm_device *dev,
+		struct dma_buf_attachment *attach, struct sg_table *sgt)
+{
+	return NULL;
+}
+
+static void *prime_vmap(struct drm_gem_object *obj)
+{
+	return NULL;
+}
+
+static void prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+}
+
+static int prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+static const struct file_operations xendrm_fops = {
+	.owner          = THIS_MODULE,
+	.open           = drm_open,
+	.release        = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = drm_compat_ioctl,
+#endif
+	.poll           = drm_poll,
+	.read           = drm_read,
+	.llseek         = no_llseek,
+	.mmap           = gem_mmap,
+};
+
+static const struct vm_operations_struct xen_drm_vm_ops = {
+	.open           = drm_gem_vm_open,
+	.close          = drm_gem_vm_close,
+};
+
+struct drm_driver xen_drm_driver = {
+	.driver_features           = DRIVER_GEM | DRIVER_MODESET |
+				     DRIVER_PRIME | DRIVER_ATOMIC,
+	.lastclose                 = lastclose,
+	.gem_free_object_unlocked  = free_object,
+	.gem_vm_ops                = &xen_drm_vm_ops,
+	.prime_handle_to_fd        = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle        = drm_gem_prime_fd_to_handle,
+	.gem_prime_import          = drm_gem_prime_import,
+	.gem_prime_export          = drm_gem_prime_export,
+	.gem_prime_get_sg_table    = prime_get_sg_table,
+	.gem_prime_import_sg_table = prime_import_sg_table,
+	.gem_prime_vmap            = prime_vmap,
+	.gem_prime_vunmap          = prime_vunmap,
+	.gem_prime_mmap            = prime_mmap,
+	.dumb_create               = dumb_create,
+	.fops                      = &xendrm_fops,
+	.name                      = "xendrm-du",
+	.desc                      = "Xen PV DRM Display Unit",
+	.date                      = "20161109",
+	.major                     = 1,
+	.minor                     = 0,
+};
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops)
+{
+	struct xen_drm_front_cfg *cfg = dev_get_platdata(&pdev->dev);
+	struct xen_drm_front_drm_info *drm_info;
+	struct drm_device *dev;
+	int ret;
+
+	DRM_INFO("Creating %s\n", xen_drm_driver.desc);
+
+	drm_info = devm_kzalloc(&pdev->dev, sizeof(*drm_info), GFP_KERNEL);
+	if (!drm_info)
+		return -ENOMEM;
+
+	drm_info->front_ops = front_ops;
+	drm_info->front_ops->on_frame_done = on_frame_done;
+	drm_info->front_info = cfg->front_info;
+
+	dev = drm_dev_alloc(&xen_drm_driver, &pdev->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	drm_info->drm_dev = dev;
+
+	drm_info->cfg = cfg;
+	dev->dev_private = drm_info;
+	platform_set_drvdata(pdev, drm_info);
+
+	ret = drm_vblank_init(dev, cfg->num_connectors);
+	if (ret) {
+		DRM_ERROR("Failed to initialize vblank, ret %d\n", ret);
+		return ret;
+	}
+
+	dev->irq_enabled = 1;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		goto fail_register;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+			xen_drm_driver.name, xen_drm_driver.major,
+			xen_drm_driver.minor, xen_drm_driver.patchlevel,
+			xen_drm_driver.date, dev->primary->index);
+
+	return 0;
+
+fail_register:
+	drm_dev_unregister(dev);
+	drm_mode_config_cleanup(dev);
+	return ret;
+}
+
+int xen_drm_front_drv_remove(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev = drm_info->drm_dev;
+
+	if (dev) {
+		drm_dev_unregister(dev);
+		drm_atomic_helper_shutdown(dev);
+		drm_mode_config_cleanup(dev);
+		drm_dev_unref(dev);
+	}
+	return 0;
+}
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev)
+{
+	struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+	struct drm_device *dev;
+
+	if (!drm_info)
+		return false;
+
+	dev = drm_info->drm_dev;
+	if (!dev)
+		return false;
+
+	/*
+	 * FIXME: the code below must be protected by drm_global_mutex,
+	 * but it is not accessible to us. Anyways there is a race condition,
+	 * but we will re-try.
+	 */
+	return dev->open_count != 0;
+}
drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0
new file mode 100644
index 000000000000..aaa476535c13
@@ -0,0 +1,60 @@
+/*
+ *  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 <[email protected]>
+ */
+
+#ifndef __XEN_DRM_FRONT_DRV_H_
+#define __XEN_DRM_FRONT_DRV_H_
+
+#include <drm/drmP.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_cfg.h"
+
+struct xen_drm_front_drm_pipeline {
+	struct xen_drm_front_drm_info *drm_info;
+
+	int index;
+};
+
+struct xen_drm_front_drm_info {
+	struct xen_drm_front_info *front_info;
+	struct xen_drm_front_ops *front_ops;
+	struct drm_device *drm_dev;
+	struct xen_drm_front_cfg *cfg;
+};
+
+static inline uint64_t xen_drm_front_fb_to_cookie(
+		struct drm_framebuffer *fb)
+{
+	return (uint64_t)fb;
+}
+
+static inline uint64_t xen_drm_front_dbuf_to_cookie(
+		struct drm_gem_object *gem_obj)
+{
+	return (uint64_t)gem_obj;
+}
+
+int xen_drm_front_drv_probe(struct platform_device *pdev,
+		struct xen_drm_front_ops *front_ops);
+
+int xen_drm_front_drv_remove(struct platform_device *pdev);
+
+bool xen_drm_front_drv_is_used(struct platform_device *pdev);
+
+#endif /* __XEN_DRM_FRONT_DRV_H_ */
+
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 8 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#54 lore raw

PATCH 6/9 drm/xen-front: Introduce DRM/KMS virtual display driver

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement essential initialization of the display driver:
- introduce required data structures
- handle DRM/KMS driver registration
- perform basic DRM driver initialization
- register driver on backend connection
- remove driver on backend disconnect
- introduce essential callbacks required by DRM/KMS core
- introduce essential callbacks required for frontend operations

---
 drivers/gpu/drm/xen/Makefile            |   1 +
 drivers/gpu/drm/xen/xen_drm_front.c     | 169 ++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h     |  24 ++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c | 211 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.h |  60 +++++++++
 5 files changed, 462 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_drv.h
drivers/gpu/drm/xen/Makefile +1 -0
index f1823cb596c5..d3068202590f 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 drm_xen_front-objs := xen_drm_front.o \
+		      xen_drm_front_drv.o \
 		      xen_drm_front_evtchnl.o \
 		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
drivers/gpu/drm/xen/xen_drm_front.c +166 -3

206 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front.h +24 -0
index 13f22736ae02..9ed5bfb248d0 100644
@@ -19,6 +19,8 @@
 #ifndef __XEN_DRM_FRONT_H_
 #define __XEN_DRM_FRONT_H_
 
+#include <linux/scatterlist.h>
+
 #include "xen_drm_front_cfg.h"
 
 #ifndef GRANT_INVALID_REF
@@ -30,16 +32,38 @@
 #define GRANT_INVALID_REF	0
 #endif
 
+struct xen_drm_front_drm_pipeline;
+
 struct xen_drm_front_ops {
+	int (*mode_set)(struct xen_drm_front_drm_pipeline *pipeline,
+			uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t fb_cookie);
+	int (*dbuf_create_from_pages)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct page **pages);
+	int (*dbuf_create_from_sgt)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint32_t width, uint32_t height,
+			uint32_t bpp, uint64_t size, struct sg_table *sgt);
+	int (*dbuf_destroy)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie);
+	int (*fb_attach)(struct xen_drm_front_info *front_info,
+			uint64_t dbuf_cookie, uint64_t fb_cookie,
+			uint32_t width, uint32_t height, uint32_t pixel_format);
+	int (*fb_detach)(struct xen_drm_front_info *front_info,
+			uint64_t fb_cookie);
+	int (*page_flip)(struct xen_drm_front_info *front_info,
+			int conn_idx, uint64_t fb_cookie);
 	/* CAUTION! this is called with a spin_lock held! */
 	void (*on_frame_done)(struct platform_device *pdev,
 			int conn_idx, uint64_t fb_cookie);
+	void (*drm_last_close)(struct xen_drm_front_info *front_info);
 };
 
 struct xen_drm_front_info {
 	struct xenbus_device *xb_dev;
 	/* to protect data between backend IO code and interrupt handler */
 	spinlock_t io_lock;
+	bool drm_pdrv_registered;
 	/* virtual DRM platform device */
 	struct platform_device *drm_pdev;
 
drivers/gpu/drm/xen/xen_drm_front_drv.c new file +211 -0

211 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_drv.h new file +60 -0

60 lines not on this page · raw message

Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#55 lore raw

PATCH 7/9 drm/xen-front: Implement KMS/connector handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

---
 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
drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0

125 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
 }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +299 -0

299 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#56 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

Quoted 19 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 7 lines

- 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

I think once you've removed the midlayer in the previous patch it would makes sense to merge the 2 patches into 1.

Bunch more comments below.
-Daniel

Quoted 391 lines
---
 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
drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
 }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +101 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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;

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+
+	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.

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.

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+
+	if (ret)
+		DRM_ERROR("Failed to set mode to back: %d\n", ret);
+
+	return ret;

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+}
+
+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), you also don't have a enable/disable_vblank implementation. If there's no vblank handling then this shouldn't be needed.

Quoted 16 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +16 -0
+	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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+		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) 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.

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.

Quoted 45 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +45 -0
+}
+
+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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+
+	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.
-Daniel

Quoted 135 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#57 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 400 lines

Bunch more comments below.
-Daniel

Quoted 396 lines
---
  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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
  }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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}

Quoted 3 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 21 lines
Quoted 21 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +21 -0
+	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;
+	}
+}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+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?

Quoted 3 lines

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

Quoted 3 lines

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

Quoted 51 lines
Quoted 51 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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?

Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#58 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

Quoted 427 lines · Oleksandr Andrushchenko
Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 388 lines

Bunch more comments below.
-Daniel

Quoted 384 lines
---
  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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
  }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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.

Quoted 9 lines

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.

Yeah that's what I meant - it is needlessly confusing: You get 2 explicit enable/disable callbacks, then you squash them into 1 function call, only to require an

if (do_I_need_to_enable_or_disable) {
	/* code that really should be directly put in the enable callback */
} else {
	/* code that really should be directly put in the enable callback */
}

Just a bit of indirection where I didnt' see the point.

Aside for why this matters: When refactoring the entire subsystem you need to be able to quickly understand how all the drivers work in a specific case, without being an expert on that driver. If there's very little indirection between the shared drm concepts/structs/callbacks and the actual driver code, then that's easy. If there's a bunch of callback layers or indirections like the above, you make subsystem refactoring harder for no reason. And in upstream we optimize for the overall subsystem, not individual drivers.

Quoted 60 lines

3. I will remove this function at all and will make direct calls to the backend on .display_{enable|disable}

Quoted 3 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 21 lines
Quoted 21 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +21 -0
+	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;
+	}
+}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+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)

Quoted 3 lines

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?

Yeah you can reuse the event_lock too, that's what many drivers do.

Quoted 80 lines
Quoted 3 lines

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

Quoted 3 lines

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

Quoted 51 lines
Quoted 51 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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.

Quoted 1 line

Do you think I can remove this workaround completely?

Yes. If you want to tell userspace that the backend is gone, send a hotplug uevent and update the connector status to disconnected. Hotplug uevents is how we tell userspace about asynchronous changes. We also have special stuff to signal display cable issue that might require picking a lower resolution (DP link training) and when HDCP encryption failed.

Sending back random errors on pageflips just confuses the compositor, and all correctly working compositors will listen to hotplug events and reprobe all the outputs and change the configuration if necessary. -Daniel

Quoted 142 lines
Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#59 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

Quoted 448 lines · Daniel Vetter
Quoted 426 lines · Oleksandr Andrushchenko
Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 387 lines

Bunch more comments below.
-Daniel

Quoted 384 lines
---
   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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
   }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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.

Quoted 9 lines

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.

Yeah that's what I meant - it is needlessly confusing: You get 2 explicit enable/disable callbacks, then you squash them into 1 function call, only to require an

if (do_I_need_to_enable_or_disable) {
	/* code that really should be directly put in the enable callback */
} else {
	/* code that really should be directly put in the enable callback */
}

Just a bit of indirection where I didnt' see the point.

Quoted 8 lines

Aside for why this matters: When refactoring the entire subsystem you need to be able to quickly understand how all the drivers work in a specific case, without being an expert on that driver. If there's very little indirection between the shared drm concepts/structs/callbacks and the actual driver code, then that's easy. If there's a bunch of callback layers or indirections like the above, you make subsystem refactoring harder for no reason. And in upstream we optimize for the overall subsystem, not individual drivers.

ok, does make sense, will rework without yet another function

Quoted 59 lines
Quoted 59 lines

3. I will remove this function at all and will make direct calls to the backend on .display_{enable|disable}

Quoted 2 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 29 lines
Quoted 16 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +16 -0
+	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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+		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)

Quoted 4 lines
Quoted 3 lines

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?

Yeah you can reuse the event_lock too, that's what many drivers do.

I just was clarifying on the need for my own private lock ;)

Quoted 79 lines
Quoted 79 lines
Quoted 3 lines

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

Quoted 3 lines

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

Quoted 50 lines
Quoted 50 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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.

Quoted 6 lines
Quoted 1 line

Do you think I can remove this workaround completely?

Yes. If you want to tell userspace that the backend is gone, send a hotplug uevent and update the connector status to disconnected. Hotplug uevents is how we tell userspace about asynchronous changes. We also have special stuff to signal display cable issue that might require picking a lower resolution (DP link training) and when HDCP encryption failed.

Ah, then I'll need to plumb in connector hotplug machinery. Will add that so I can report errors

Quoted 3 lines

Sending back random errors on pageflips just confuses the compositor, and all correctly working compositors will listen to hotplug events and reprobe all the outputs and change the configuration if necessary.

Good point, thank you

Quoted 144 lines

-Daniel

Quoted 142 lines
Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#60 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

In reply to Daniel Vetter
Quoted 448 lines · Daniel Vetter
Quoted 426 lines · Oleksandr Andrushchenko
Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 387 lines

Bunch more comments below.
-Daniel

Quoted 384 lines
---
   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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
   }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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.

Quoted 9 lines

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.

Yeah that's what I meant - it is needlessly confusing: You get 2 explicit enable/disable callbacks, then you squash them into 1 function call, only to require an

if (do_I_need_to_enable_or_disable) {
	/* code that really should be directly put in the enable callback */
} else {
	/* code that really should be directly put in the enable callback */
}

Just a bit of indirection where I didnt' see the point.

Quoted 8 lines

Aside for why this matters: When refactoring the entire subsystem you need to be able to quickly understand how all the drivers work in a specific case, without being an expert on that driver. If there's very little indirection between the shared drm concepts/structs/callbacks and the actual driver code, then that's easy. If there's a bunch of callback layers or indirections like the above, you make subsystem refactoring harder for no reason. And in upstream we optimize for the overall subsystem, not individual drivers.

ok, does make sense, will rework without yet another function

Quoted 59 lines
Quoted 59 lines

3. I will remove this function at all and will make direct calls to the backend on .display_{enable|disable}

Quoted 2 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 29 lines
Quoted 16 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +16 -0
+	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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+		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)

Quoted 4 lines
Quoted 3 lines

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?

Yeah you can reuse the event_lock too, that's what many drivers do.

I just was clarifying on the need for my own private lock ;)

Quoted 79 lines
Quoted 79 lines
Quoted 3 lines

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

Quoted 3 lines

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

Quoted 50 lines
Quoted 50 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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.

Quoted 6 lines
Quoted 1 line

Do you think I can remove this workaround completely?

Yes. If you want to tell userspace that the backend is gone, send a hotplug uevent and update the connector status to disconnected. Hotplug uevents is how we tell userspace about asynchronous changes. We also have special stuff to signal display cable issue that might require picking a lower resolution (DP link training) and when HDCP encryption failed.

Ah, then I'll need to plumb in connector hotplug machinery. Will add that so I can report errors

Quoted 3 lines

Sending back random errors on pageflips just confuses the compositor, and all correctly working compositors will listen to hotplug events and reprobe all the outputs and change the configuration if necessary.

Good point, thank you

Quoted 144 lines

-Daniel

Quoted 142 lines
Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#61 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

In reply to Oleksandr Andrushchenko
Quoted 427 lines · Oleksandr Andrushchenko
Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 388 lines

Bunch more comments below.
-Daniel

Quoted 384 lines
---
  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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
  }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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.

Quoted 9 lines

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.

Yeah that's what I meant - it is needlessly confusing: You get 2 explicit enable/disable callbacks, then you squash them into 1 function call, only to require an

if (do_I_need_to_enable_or_disable) {
	/* code that really should be directly put in the enable callback */
} else {
	/* code that really should be directly put in the enable callback */
}

Just a bit of indirection where I didnt' see the point.

Aside for why this matters: When refactoring the entire subsystem you need to be able to quickly understand how all the drivers work in a specific case, without being an expert on that driver. If there's very little indirection between the shared drm concepts/structs/callbacks and the actual driver code, then that's easy. If there's a bunch of callback layers or indirections like the above, you make subsystem refactoring harder for no reason. And in upstream we optimize for the overall subsystem, not individual drivers.

Quoted 60 lines

3. I will remove this function at all and will make direct calls to the backend on .display_{enable|disable}

Quoted 3 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 21 lines
Quoted 21 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +21 -0
+	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;
+	}
+}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+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)

Quoted 3 lines

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?

Yeah you can reuse the event_lock too, that's what many drivers do.

Quoted 80 lines
Quoted 3 lines

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

Quoted 3 lines

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

Quoted 51 lines
Quoted 51 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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.

Quoted 1 line

Do you think I can remove this workaround completely?

Yes. If you want to tell userspace that the backend is gone, send a hotplug uevent and update the connector status to disconnected. Hotplug uevents is how we tell userspace about asynchronous changes. We also have special stuff to signal display cable issue that might require picking a lower resolution (DP link training) and when HDCP encryption failed.

Sending back random errors on pageflips just confuses the compositor, and all correctly working compositors will listen to hotplug events and reprobe all the outputs and change the configuration if necessary. -Daniel

Quoted 142 lines
Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Signature · 8 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#62 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

In reply to Daniel Vetter
Quoted 26 lines · Daniel Vetter
Quoted 25 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 3 lines
Quoted 1 line

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

Quoted 400 lines

Bunch more comments below.
-Daniel

Quoted 396 lines
---
  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

drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
  }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +106 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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,
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+				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}

Quoted 3 lines

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

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +9 -0
+
+	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)
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +6 -0
+{
+	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

Quoted 2 lines

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

Quoted 2 lines

If there's no vblank
handling then this shouldn't be needed.

yes, I will rework the code, please see below

Quoted 21 lines
Quoted 21 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +21 -0
+	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;
+	}
+}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+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?

Quoted 3 lines

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

Quoted 3 lines

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

Quoted 51 lines
Quoted 51 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +50 -0
+}
+
+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 */
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+		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?

Quoted 133 lines

-Daniel

Quoted 131 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 1 line
2.7.4
Quoted 4 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[1] https://patchwork.kernel.org/patch/10211997/

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#63 lore raw

Re: [PATCH 7/9] drm/xen-front: Implement KMS/connector handling

In reply to Oleksandr Andrushchenko
Quoted 19 lines · Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

Quoted 7 lines

- 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

I think once you've removed the midlayer in the previous patch it would makes sense to merge the 2 patches into 1.

Bunch more comments below.
-Daniel

Quoted 391 lines
---
 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
drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0
new file mode 100644
index 000000000000..d9986a2e1a3b
@@ -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 <[email protected]>
+ */
+
+#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);
+}
drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
 }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +101 -0
new file mode 100644
index 000000000000..ad94c28835cd
@@ -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 <[email protected]>
+ */
+
+#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;

drivers/gpu/drm/xen/xen_drm_front_kms.c line 111

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+
+	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.

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.

Quoted 5 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +5 -0
+
+	if (ret)
+		DRM_ERROR("Failed to set mode to back: %d\n", ret);
+
+	return ret;

drivers/gpu/drm/xen/xen_drm_front_kms.c line 126

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+}
+
+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), you also don't have a enable/disable_vblank implementation. If there's no vblank handling then this shouldn't be needed.

Quoted 16 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +16 -0
+	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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 152

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+		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) 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.

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.

Quoted 45 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +45 -0
+}
+
+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);

drivers/gpu/drm/xen/xen_drm_front_kms.c line 207

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +10 -0
+
+	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.
-Daniel

Quoted 135 lines
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +92 -0
+	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;
+}
drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 8 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#64 lore raw

PATCH 7/9 drm/xen-front: Implement KMS/connector handling

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

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

---
 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
drivers/gpu/drm/xen/Makefile +2 -0
index d3068202590f..4fcb0da1a9c5 100644
@@ -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
drivers/gpu/drm/xen/xen_drm_front_conn.c new file +125 -0

125 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_conn.h new file +35 -0
new file mode 100644
index 000000000000..708e80d45985
@@ -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 <[email protected]>
+ */
+
+#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_ */
drivers/gpu/drm/xen/xen_drm_front_drv.c +15 -0
index b3764d5ed0f6..e8862d26ba27 100644
@@ -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;
 }
drivers/gpu/drm/xen/xen_drm_front_drv.h +12 -0
index aaa476535c13..563318b19f34 100644
@@ -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(
drivers/gpu/drm/xen/xen_drm_front_kms.c new file +299 -0

299 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_kms.h new file +30 -0
new file mode 100644
index 000000000000..65a50033bb9b
@@ -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 <[email protected]>
+ */
+
+#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_ */
Signature · 7 lines
2.7.4


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel
#65 lore raw

PATCH 8/9 drm/xen-front: Implement GEM operations

In reply to Oleksandr Andrushchenko

From: Oleksandr Andrushchenko <[email protected]>

Implement GEM handling depending on driver mode of operation:
depending on the requirements for the para-virtualized environment, namely requirements dictated by the accompanying DRM/(v)GPU drivers running in both host and guest environments, number of operating modes of para-virtualized display driver are supported:
- display buffers can be allocated by either frontend driver or backend
- display buffers can be allocated to be contiguous in memory or not

Note! Frontend driver itself has no dependency on contiguous memory for its operation.

1. Buffers allocated by the frontend driver.

The below modes of operation are configured at compile-time via frontend driver's kernel configuration.

1.1. Front driver configured to use GEM CMA helpers
This use-case is useful when used with accompanying DRM/vGPU driver in guest domain which was designed to only work with contiguous buffers, e.g. DRM driver based on GEM CMA helpers: such drivers can only import contiguous PRIME buffers, thus requiring frontend driver to provide such. In order to implement this mode of operation para-virtualized frontend driver can be configured to use GEM CMA helpers.

1.2. Front driver doesn't use GEM CMA
If accompanying drivers can cope with non-contiguous memory then, to lower pressure on CMA subsystem of the kernel, driver can allocate buffers from system memory.

Note! If used with accompanying DRM/(v)GPU drivers this mode of operation may require IOMMU support on the platform, so accompanying DRM/vGPU hardware can still reach display buffer memory while importing PRIME buffers from the frontend driver.

2. Buffers allocated by the backend

This mode of operation is run-time configured via guest domain configuration through XenStore entries.

For systems which do not provide IOMMU support, but having specific requirements for display buffers it is possible to allocate such buffers at backend side and share those with the frontend.
For example, if host domain is 1:1 mapped and has DRM/GPU hardware expecting physically contiguous memory, this allows implementing zero-copying use-cases.

Note! Configuration options 1.1 (contiguous display buffers) and 2 (backend allocated buffers) are not supported at the same time.

---
 drivers/gpu/drm/xen/Kconfig                 |  13 +
 drivers/gpu/drm/xen/Makefile                |   6 +
 drivers/gpu/drm/xen/xen_drm_front.h         |  74 ++++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c     |  80 ++++++-
 drivers/gpu/drm/xen/xen_drm_front_drv.h     |   1 +
 drivers/gpu/drm/xen/xen_drm_front_gem.c     | 360 ++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_gem.h     |  46 ++++
 drivers/gpu/drm/xen/xen_drm_front_gem_cma.c |  93 +++++++
 8 files changed, 667 insertions(+), 6 deletions(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_gem_cma.c
drivers/gpu/drm/xen/Kconfig +13 -0
index 4cca160782ab..4f4abc91f3b6 100644
@@ -15,3 +15,16 @@ config DRM_XEN_FRONTEND
 	help
 	  Choose this option if you want to enable a para-virtualized
 	  frontend DRM/KMS driver for Xen guest OSes.
+
+config DRM_XEN_FRONTEND_CMA
+	bool "Use DRM CMA to allocate dumb buffers"
+	depends on DRM_XEN_FRONTEND
+	select DRM_KMS_CMA_HELPER
+	select DRM_GEM_CMA_HELPER
+	help
+	  Use DRM CMA helpers to allocate display buffers.
+	  This is useful for the use-cases when guest driver needs to
+	  share or export buffers to other drivers which only expect
+	  contiguous buffers.
+	  Note: in this mode driver cannot use buffers allocated
+	  by the backend.
drivers/gpu/drm/xen/Makefile +6 -0
index 4fcb0da1a9c5..12376ec78fbc 100644
@@ -8,4 +8,10 @@ drm_xen_front-objs := xen_drm_front.o \
 		      xen_drm_front_shbuf.o \
 		      xen_drm_front_cfg.o
 
+ifeq ($(CONFIG_DRM_XEN_FRONTEND_CMA),y)
+	drm_xen_front-objs += xen_drm_front_gem_cma.o
+else
+	drm_xen_front-objs += xen_drm_front_gem.o
+endif
+
 obj-$(CONFIG_DRM_XEN_FRONTEND) += drm_xen_front.o
drivers/gpu/drm/xen/xen_drm_front.h +74 -0

80 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_drv.c +74 -6

130 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_drv.h +1 -0
index 563318b19f34..34228eb86255 100644
@@ -43,6 +43,7 @@ struct xen_drm_front_drm_pipeline {
 struct xen_drm_front_drm_info {
 	struct xen_drm_front_info *front_info;
 	struct xen_drm_front_ops *front_ops;
+	const struct xen_drm_front_gem_ops *gem_ops;
 	struct drm_device *drm_dev;
 	struct xen_drm_front_cfg *cfg;
 
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +360 -0

360 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_gem.h new file +46 -0

46 lines not on this page · raw message

drivers/gpu/drm/xen/xen_drm_front_gem_cma.c new file +93 -0

93 lines not on this page · raw message

Signature · 6 lines
2.7.4

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#66 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 7 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +7 -0
+static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+	struct xen_gem_object *xen_obj;
+	int ret;
+
+	size = round_up(size, PAGE_SIZE);

drivers/gpu/drm/xen/xen_drm_front_gem.c line 105

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +10 -0
+	xen_obj = gem_create_obj(dev, size);
+	if (IS_ERR_OR_NULL(xen_obj))
+		return xen_obj;
+
+	if (drm_info->cfg->be_alloc) {
+		/*
+		 * backend will allocate space for this buffer, so
+		 * only allocate array of pointers to pages
+		 */
+		xen_obj->be_alloc = true;

If be_alloc is a flag (which I am not sure about) --- should it be set to true *after* you've successfully allocated your things?

drivers/gpu/drm/xen/xen_drm_front_gem.c line 113

Quoted 8 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +8 -0
+		ret = gem_alloc_pages_array(xen_obj, size);
+		if (ret < 0) {
+			gem_free_pages_array(xen_obj);
+			goto fail;
+		}
+
+		ret = alloc_xenballooned_pages(xen_obj->num_pages,
+				xen_obj->pages);

Why are you allocating balloon pages?

-boris

Quoted 18 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +17 -0
+		if (ret < 0) {
+			DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
+					xen_obj->num_pages, ret);
+			goto fail;
+		}
+
+		return xen_obj;
+	}
+	/*
+	 * need to allocate backing pages now, so we can share those
+	 * with the backend
+	 */
+	xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+	xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+	if (IS_ERR_OR_NULL(xen_obj->pages)) {
+		ret = PTR_ERR(xen_obj->pages);
+		xen_obj->pages = NULL;

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +10 -0
+		goto fail;
+	}
+
+	return xen_obj;
+
+fail:
+	DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+	return ERR_PTR(ret);
+}
+

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#67 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 12 lines · Boris Ostrovsky
Quoted 11 lines · Oleksandr Andrushchenko
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +11 -0
+static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)
+{
+	struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+	struct xen_gem_object *xen_obj;
+	int ret;
+
+	size = round_up(size, PAGE_SIZE);
+	xen_obj = gem_create_obj(dev, size);
+	if (IS_ERR_OR_NULL(xen_obj))
+		return xen_obj;
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 105

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+	if (drm_info->cfg->be_alloc) {
+		/*
+		 * backend will allocate space for this buffer, so
+		 * only allocate array of pointers to pages
+		 */
+		xen_obj->be_alloc = true;

If be_alloc is a flag (which I am not sure about) --- should it be set to true *after* you've successfully allocated your things?

this is a configuration option telling about the way the buffer gets allocated: either by the frontend or backend (be_alloc -> buffer allocated by the backend)

Quoted 10 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 113

Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +8 -0
+		ret = gem_alloc_pages_array(xen_obj, size);
+		if (ret < 0) {
+			gem_free_pages_array(xen_obj);
+			goto fail;
+		}
+
+		ret = alloc_xenballooned_pages(xen_obj->num_pages,
+				xen_obj->pages);

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:
 *******************************************************************************
 * 2. Buffers allocated by the backend
 *******************************************************************************
 *
 * This mode of operation is run-time configured via guest domain configuration
 * through XenStore entries.
 *
 * For systems which do not provide IOMMU support, but having specific
 * requirements for display buffers it is possible to allocate such buffers
 * at backend side and share those with the frontend.
 * For example, if host domain is 1:1 mapped and has DRM/GPU hardware expecting
 * physically contiguous memory, this allows implementing zero-copying
 * use-cases.

Quoted 23 lines

-boris

Quoted 20 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +20 -0
+		if (ret < 0) {
+			DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
+					xen_obj->num_pages, ret);
+			goto fail;
+		}
+
+		return xen_obj;
+	}
+	/*
+	 * need to allocate backing pages now, so we can share those
+	 * with the backend
+	 */
+	xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+	xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+	if (IS_ERR_OR_NULL(xen_obj->pages)) {
+		ret = PTR_ERR(xen_obj->pages);
+		xen_obj->pages = NULL;
+		goto fail;
+	}
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +7 -0
+	return xen_obj;
+
+fail:
+	DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+	return ERR_PTR(ret);
+}
+

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#68 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 22 lines · Oleksandr Andrushchenko
Quoted 13 lines · Boris Ostrovsky
Quoted 12 lines · Oleksandr Andrushchenko

+static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +10 -0
+{
+    struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+    struct xen_gem_object *xen_obj;
+    int ret;
+
+    size = round_up(size, PAGE_SIZE);
+    xen_obj = gem_create_obj(dev, size);
+    if (IS_ERR_OR_NULL(xen_obj))
+        return xen_obj;
+
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 105

Quoted 6 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+    if (drm_info->cfg->be_alloc) {
+        /*
+         * backend will allocate space for this buffer, so
+         * only allocate array of pointers to pages
+         */
+        xen_obj->be_alloc = true;

If be_alloc is a flag (which I am not sure about) --- should it be set to true *after* you've successfully allocated your things?

Quoted 3 lines

this is a configuration option telling about the way the buffer gets allocated: either by the frontend or backend (be_alloc -> buffer allocated by the backend)

I can see how drm_info->cfg->be_alloc might be a configuration option but xen_obj->be_alloc is set here and that's not how configuration options typically behave.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +8 -0
+        ret = gem_alloc_pages_array(xen_obj, size);
+        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages,
+                xen_obj->pages);
Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

-boris

Quoted 54 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:
*******************************************************************************

* 2. Buffers allocated by the backend
*******************************************************************************

*
* This mode of operation is run-time configured via guest domain
configuration
* through XenStore entries.
*
* For systems which do not provide IOMMU support, but having specific
* requirements for display buffers it is possible to allocate such
buffers
* at backend side and share those with the frontend.
* For example, if host domain is 1:1 mapped and has DRM/GPU hardware
expecting
* physically contiguous memory, this allows implementing zero-copying
* use-cases.

Quoted 31 lines

-boris

Quoted 28 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +27 -0
+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
+                    xen_obj->num_pages, ret);
+            goto fail;
+        }
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
+    return xen_obj;
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+
#69 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 23 lines · Boris Ostrovsky
Quoted 22 lines · Oleksandr Andrushchenko
Quoted 21 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+{
+    struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+    struct xen_gem_object *xen_obj;
+    int ret;
+
+    size = round_up(size, PAGE_SIZE);

drivers/gpu/drm/xen/xen_drm_front_gem.c line 105

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +10 -0
+    xen_obj = gem_create_obj(dev, size);
+    if (IS_ERR_OR_NULL(xen_obj))
+        return xen_obj;
+
+    if (drm_info->cfg->be_alloc) {
+        /*
+         * backend will allocate space for this buffer, so
+         * only allocate array of pointers to pages
+         */
+        xen_obj->be_alloc = true;

If be_alloc is a flag (which I am not sure about) --- should it be set to true *after* you've successfully allocated your things?

Quoted 7 lines
Quoted 3 lines

this is a configuration option telling about the way the buffer gets allocated: either by the frontend or backend (be_alloc -> buffer allocated by the backend)

I can see how drm_info->cfg->be_alloc might be a configuration option but xen_obj->be_alloc is set here and that's not how configuration options typically behave.

you are right, I will put be_alloc down the code and will slightly rework error handling for this function

Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +8 -0
+        ret = gem_alloc_pages_array(xen_obj, size);
+        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages,
+                xen_obj->pages);
Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 45 lines

-boris

Quoted 43 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:
*******************************************************************************

* 2. Buffers allocated by the backend
*******************************************************************************

*
* This mode of operation is run-time configured via guest domain
configuration
* through XenStore entries.
*
* For systems which do not provide IOMMU support, but having specific
* requirements for display buffers it is possible to allocate such
buffers
* at backend side and share those with the frontend.
* For example, if host domain is 1:1 mapped and has DRM/GPU hardware
expecting
* physically contiguous memory, this allows implementing zero-copying
* use-cases.

Quoted 22 lines

-boris

Quoted 20 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +20 -0
+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
+                    xen_obj->num_pages, ret);
+            goto fail;
+        }
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +7 -0
+    return xen_obj;
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

[1] https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#70 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 31 lines · Oleksandr Andrushchenko
Quoted 20 lines · Boris Ostrovsky
Quoted 11 lines · Oleksandr Andrushchenko
Quoted 10 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+        ret = gem_alloc_pages_array(xen_obj, size); +        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages, +                xen_obj->pages);

Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

Quoted 6 lines

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

How will dom0/backend know whether or not to trust the front end (and thus whether or not to provide provide pages to it)? Will there be something in xenstore, for example, to indicate such trusted frontends?

-boris

Quoted 63 lines

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 47 lines

-boris

Quoted 45 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:

*******************************************************************************

  * 2. Buffers allocated by the backend

*******************************************************************************

  *
  * This mode of operation is run-time configured via guest domain configuration
  * through XenStore entries.
  *
  * For systems which do not provide IOMMU support, but having specific
  * requirements for display buffers it is possible to allocate such buffers
  * at backend side and share those with the frontend.
  * For example, if host domain is 1:1 mapped and has DRM/GPU hardware expecting
  * physically contiguous memory, this allows implementing zero-copying
  * use-cases.

Quoted 22 lines

-boris

Quoted 20 lines

+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n", +                    xen_obj->num_pages, ret);
+            goto fail;
+        }

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +15 -0
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines

+    return xen_obj;

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

Quoted 3 lines

[1]
https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#71 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

In reply to Oleksandr Andrushchenko
Quoted 31 lines · Oleksandr Andrushchenko
Quoted 20 lines · Boris Ostrovsky
Quoted 11 lines · Oleksandr Andrushchenko
Quoted 10 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+        ret = gem_alloc_pages_array(xen_obj, size); +        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages, +                xen_obj->pages);

Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

Quoted 6 lines

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

How will dom0/backend know whether or not to trust the front end (and thus whether or not to provide provide pages to it)? Will there be something in xenstore, for example, to indicate such trusted frontends?

-boris

Quoted 66 lines

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 47 lines

-boris

Quoted 45 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:

*******************************************************************************

  * 2. Buffers allocated by the backend

*******************************************************************************

  *
  * This mode of operation is run-time configured via guest domain configuration
  * through XenStore entries.
  *
  * For systems which do not provide IOMMU support, but having specific
  * requirements for display buffers it is possible to allocate such buffers
  * at backend side and share those with the frontend.
  * For example, if host domain is 1:1 mapped and has DRM/GPU hardware expecting
  * physically contiguous memory, this allows implementing zero-copying
  * use-cases.

Quoted 22 lines

-boris

Quoted 20 lines

+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n", +                    xen_obj->num_pages, ret);
+            goto fail;
+        }

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +15 -0
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines

+    return xen_obj;

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

[1]
https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html

#72 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

Quoted 37 lines · Boris Ostrovsky
Quoted 29 lines · Oleksandr Andrushchenko
Quoted 18 lines · Boris Ostrovsky
Quoted 10 lines · Oleksandr Andrushchenko
Quoted 9 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+        ret = gem_alloc_pages_array(xen_obj, size); +        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages, +                xen_obj->pages);

Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

Quoted 6 lines

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

Quoted 3 lines

How will dom0/backend know whether or not to trust the front end (and thus whether or not to provide provide pages to it)? Will there be something in xenstore, for example, to indicate such trusted frontends?

Exactly, there is a dedicated xl configuration option available [1] for vdispl:

"be-alloc=BOOLEAN
Indicates if backend can be a buffer provider/allocator for this domain. See display protocol for details."

Thus, one can configure this per domain for trusted ones in corresponding xl configuration files

Quoted 68 lines

-boris

Quoted 65 lines

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 47 lines

-boris

Quoted 45 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:

*******************************************************************************

  * 2. Buffers allocated by the backend

*******************************************************************************

  *
  * This mode of operation is run-time configured via guest domain
configuration
  * through XenStore entries.
  *
  * For systems which do not provide IOMMU support, but having specific
  * requirements for display buffers it is possible to allocate such
buffers
  * at backend side and share those with the frontend.
  * For example, if host domain is 1:1 mapped and has DRM/GPU hardware
expecting
  * physically contiguous memory, this allows implementing zero-copying
  * use-cases.

Quoted 22 lines

-boris

Quoted 20 lines

+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n", +                    xen_obj->num_pages, ret);
+            goto fail;
+        }

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +15 -0
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines

+    return xen_obj;

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

[1]
https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html

[1] https://xenbits.xen.org/docs/4.10-testing/man/xl.cfg.5.html

Indicates if backend can be a buffer provider/allocator for this domain. See display protocol for details.

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#73 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

In reply to Boris Ostrovsky
Quoted 37 lines · Boris Ostrovsky
Quoted 29 lines · Oleksandr Andrushchenko
Quoted 18 lines · Boris Ostrovsky
Quoted 10 lines · Oleksandr Andrushchenko
Quoted 9 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+        ret = gem_alloc_pages_array(xen_obj, size); +        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages, +                xen_obj->pages);

Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

Quoted 6 lines

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

Quoted 3 lines

How will dom0/backend know whether or not to trust the front end (and thus whether or not to provide provide pages to it)? Will there be something in xenstore, for example, to indicate such trusted frontends?

Exactly, there is a dedicated xl configuration option available [1] for vdispl:

"be-alloc=BOOLEAN
Indicates if backend can be a buffer provider/allocator for this domain. See display protocol for details."

Thus, one can configure this per domain for trusted ones in corresponding xl configuration files

Quoted 68 lines

-boris

Quoted 65 lines

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 47 lines

-boris

Quoted 45 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:

*******************************************************************************

  * 2. Buffers allocated by the backend

*******************************************************************************

  *
  * This mode of operation is run-time configured via guest domain
configuration
  * through XenStore entries.
  *
  * For systems which do not provide IOMMU support, but having specific
  * requirements for display buffers it is possible to allocate such
buffers
  * at backend side and share those with the frontend.
  * For example, if host domain is 1:1 mapped and has DRM/GPU hardware
expecting
  * physically contiguous memory, this allows implementing zero-copying
  * use-cases.

Quoted 22 lines

-boris

Quoted 20 lines

+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n", +                    xen_obj->num_pages, ret);
+            goto fail;
+        }

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +15 -0
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines

+    return xen_obj;

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

[1]
https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html

[1] https://xenbits.xen.org/docs/4.10-testing/man/xl.cfg.5.html

Indicates if backend can be a buffer provider/allocator for this domain. See display protocol for details.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel

#74 lore raw

Re: [PATCH 8/9] drm/xen-front: Implement GEM operations

In reply to Boris Ostrovsky
Quoted 23 lines · Boris Ostrovsky
Quoted 22 lines · Oleksandr Andrushchenko
Quoted 21 lines · Boris Ostrovsky
Quoted 8 lines · Oleksandr Andrushchenko

+static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)

drivers/gpu/drm/xen/xen_drm_front_gem.c new file +6 -0
+{
+    struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+    struct xen_gem_object *xen_obj;
+    int ret;
+
+    size = round_up(size, PAGE_SIZE);

drivers/gpu/drm/xen/xen_drm_front_gem.c line 105

Quoted 10 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +10 -0
+    xen_obj = gem_create_obj(dev, size);
+    if (IS_ERR_OR_NULL(xen_obj))
+        return xen_obj;
+
+    if (drm_info->cfg->be_alloc) {
+        /*
+         * backend will allocate space for this buffer, so
+         * only allocate array of pointers to pages
+         */
+        xen_obj->be_alloc = true;

If be_alloc is a flag (which I am not sure about) --- should it be set to true *after* you've successfully allocated your things?

Quoted 7 lines
Quoted 3 lines

this is a configuration option telling about the way the buffer gets allocated: either by the frontend or backend (be_alloc -> buffer allocated by the backend)

I can see how drm_info->cfg->be_alloc might be a configuration option but xen_obj->be_alloc is set here and that's not how configuration options typically behave.

you are right, I will put be_alloc down the code and will slightly rework error handling for this function

Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +8 -0
+        ret = gem_alloc_pages_array(xen_obj, size);
+        if (ret < 0) {
+            gem_free_pages_array(xen_obj);
+            goto fail;
+        }
+
+        ret = alloc_xenballooned_pages(xen_obj->num_pages,
+                xen_obj->pages);
Quoted 7 lines
Quoted 1 line

Why are you allocating balloon pages?

in this use-case we map pages provided by the backend (yes, I know this can be a problem from both security POV and that DomU can die holding pages of Dom0 forever:
but still it is a configuration option, so user decides if her use-case needs this and takes responsibility for such a decision).

Quoted 3 lines

Perhaps I am missing something here but when you say "I know this can be a problem from both security POV ..." then there is something wrong with your solution.

well, in this scenario there are actually 2 concerns:
1. If DomU dies the pages/grants from Dom0/DomD cannot be reclaimed back
2. Misbehaving guest may send too many requests to the backend exhausting grant references and memory of Dom0/DomD (this is the only concern from security POV). Please see [1]

But, we are focusing on embedded use-cases,
so those systems we use are not that "dynamic" with respect to 2).
Namely: we have fixed number of domains and their functionality is well known, so we can do rather precise assumption on resource usage. This is why I try to warn on such a use-case and rely on the end user who understands the caveats

I'll probably add more precise description of this use-case clarifying what is that security POV, so there is no confusion

Hope this explanation answers your questions

Quoted 45 lines

-boris

Quoted 43 lines

Please see description of the buffering modes in xen_drm_front.h specifically for backend allocated buffers:
*******************************************************************************

* 2. Buffers allocated by the backend
*******************************************************************************

*
* This mode of operation is run-time configured via guest domain
configuration
* through XenStore entries.
*
* For systems which do not provide IOMMU support, but having specific
* requirements for display buffers it is possible to allocate such
buffers
* at backend side and share those with the frontend.
* For example, if host domain is 1:1 mapped and has DRM/GPU hardware
expecting
* physically contiguous memory, this allows implementing zero-copying
* use-cases.

Quoted 22 lines

-boris

Quoted 20 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +20 -0
+        if (ret < 0) {
+            DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
+                    xen_obj->num_pages, ret);
+            goto fail;
+        }
+
+        return xen_obj;
+    }
+    /*
+     * need to allocate backing pages now, so we can share those
+     * with the backend
+     */
+    xen_obj->num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+    xen_obj->pages = drm_gem_get_pages(&xen_obj->base);
+    if (IS_ERR_OR_NULL(xen_obj->pages)) {
+        ret = PTR_ERR(xen_obj->pages);
+        xen_obj->pages = NULL;
+        goto fail;
+    }
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/gpu/drm/xen/xen_drm_front_gem.c line 140

Quoted 8 lines
drivers/gpu/drm/xen/xen_drm_front_gem.c new file +7 -0
+    return xen_obj;
+
+fail:
+    DRM_ERROR("Failed to allocate buffer with size %zu\n", size);
+    return ERR_PTR(ret);
+}
+

Thank you,
Oleksandr

[1] https://lists.xenproject.org/archives/html/xen-devel/2017-07/msg03100.html

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xenproject.org/mailman/listinfo/xen-devel