All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-18 10:29 ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simpledrm, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simpledrm is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simpledrm can also
serve as interim solution on graphics hardware without native DRM driver.

So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simpledrm.

Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simpledrm before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

I've also been working on fastboot support (i.e., flicker-free booting).
This requires state-readout from simpledrm via generic interfaces, as
outlined in [1]. I do have some prototype code, but it will take a while
to get this ready. Simpledrm will then support it.

I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works. I looked into X11, but couldn't see
an easy way of fixing the problem. With the push towards Wayland+Xwayland
I expect the problem to become a non-issue soon. Additional testing has
been reported at [2].

One cosmetical issue is that simpledrm's device file is card0 and the
native driver's device file is card1. After simpledrm has been kicked out,
only card1 is left. This does not seem to be a practical problem however.

TODO/IDEAS:

	* provide deferred takeover
	* provide bootsplash DRM client
	* make simplekms usable with ARM-EFI fbs

v2:
	* rename to simpledrm, aperture helpers
	* reorganized patches
	* use hotplug helpers for removal (Daniel)
	* added DT match tables (Rob)
	* use shadow-plane helpers
	* lots of minor cleanups

[1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
[2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/

Thomas Zimmermann (10):
  drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
  drm/format-helper: Add blitter functions
  drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  drm/aperture: Add infrastructure for aperture ownership
  drm: Add simpledrm driver
  drm/simpledrm: Add fbdev emulation
  drm/simpledrm: Initialize framebuffer data from device-tree node
  drm/simpledrm: Acquire clocks from DT device node
  drm/simpledrm: Acquire regulators from DT device node
  drm/simpledrm: Acquire memory aperture for framebuffer

 Documentation/gpu/drm-internals.rst    |  12 +
 MAINTAINERS                            |   7 +
 drivers/gpu/drm/Kconfig                |   7 +
 drivers/gpu/drm/Makefile               |   1 +
 drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
 drivers/gpu/drm/drm_format_helper.c    |  96 ++-
 drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
 drivers/gpu/drm/tiny/Kconfig           |  17 +
 drivers/gpu/drm/tiny/Makefile          |   1 +
 drivers/gpu/drm/tiny/cirrus.c          |   2 +-
 drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
 include/drm/drm_aperture.h             |  96 +++
 include/drm/drm_fb_helper.h            |  56 +-
 include/drm/drm_format_helper.h        |  10 +-
 14 files changed, 1466 insertions(+), 60 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
 create mode 100644 include/drm/drm_aperture.h

--
2.30.1


^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-18 10:29 ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simpledrm, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simpledrm is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simpledrm can also
serve as interim solution on graphics hardware without native DRM driver.

So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simpledrm.

Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simpledrm before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

I've also been working on fastboot support (i.e., flicker-free booting).
This requires state-readout from simpledrm via generic interfaces, as
outlined in [1]. I do have some prototype code, but it will take a while
to get this ready. Simpledrm will then support it.

I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works. I looked into X11, but couldn't see
an easy way of fixing the problem. With the push towards Wayland+Xwayland
I expect the problem to become a non-issue soon. Additional testing has
been reported at [2].

One cosmetical issue is that simpledrm's device file is card0 and the
native driver's device file is card1. After simpledrm has been kicked out,
only card1 is left. This does not seem to be a practical problem however.

TODO/IDEAS:

	* provide deferred takeover
	* provide bootsplash DRM client
	* make simplekms usable with ARM-EFI fbs

v2:
	* rename to simpledrm, aperture helpers
	* reorganized patches
	* use hotplug helpers for removal (Daniel)
	* added DT match tables (Rob)
	* use shadow-plane helpers
	* lots of minor cleanups

[1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
[2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/

Thomas Zimmermann (10):
  drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
  drm/format-helper: Add blitter functions
  drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  drm/aperture: Add infrastructure for aperture ownership
  drm: Add simpledrm driver
  drm/simpledrm: Add fbdev emulation
  drm/simpledrm: Initialize framebuffer data from device-tree node
  drm/simpledrm: Acquire clocks from DT device node
  drm/simpledrm: Acquire regulators from DT device node
  drm/simpledrm: Acquire memory aperture for framebuffer

 Documentation/gpu/drm-internals.rst    |  12 +
 MAINTAINERS                            |   7 +
 drivers/gpu/drm/Kconfig                |   7 +
 drivers/gpu/drm/Makefile               |   1 +
 drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
 drivers/gpu/drm/drm_format_helper.c    |  96 ++-
 drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
 drivers/gpu/drm/tiny/Kconfig           |  17 +
 drivers/gpu/drm/tiny/Makefile          |   1 +
 drivers/gpu/drm/tiny/cirrus.c          |   2 +-
 drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
 include/drm/drm_aperture.h             |  96 +++
 include/drm/drm_fb_helper.h            |  56 +-
 include/drm/drm_format_helper.h        |  10 +-
 14 files changed, 1466 insertions(+), 60 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
 create mode 100644 include/drm/drm_aperture.h

--
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-18 10:29 ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

This patchset adds support for simple-framebuffer platform devices and
a handover mechanism for native drivers to take-over control of the
hardware.

The new driver, called simpledrm, binds to a simple-frambuffer platform
device. The kernel's boot code creates such devices for firmware-provided
framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
loader sets up the framebuffers. Description via device tree is also an
option.

Simpledrm is small enough to be linked into the kernel. The driver's main
purpose is to provide graphical output during the early phases of the boot
process, before the native DRM drivers are available. Native drivers are
typically loaded from an initrd ram disk. Occationally simpledrm can also
serve as interim solution on graphics hardware without native DRM driver.

So far distributions rely on fbdev drivers, such as efifb, vesafb or
simplefb, for early-boot graphical output. However fbdev is deprecated and
the drivers do not provide DRM interfaces for modern userspace.

Patches 1 and 2 prepare the DRM format helpers for simpledrm.

Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
framebuffer's I/O-memory range and provides a callback function to be
removed by a native driver. The native driver will remove simpledrm before
taking over the hardware. The removal is integrated into existing helpers,
so drivers use it automatically.

Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
pageflips, SHMEM buffers are copied into the framebuffer memory, similar
to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
regulators. It's based on the simplefb drivers, but has been modified for
DRM.

I've also been working on fastboot support (i.e., flicker-free booting).
This requires state-readout from simpledrm via generic interfaces, as
outlined in [1]. I do have some prototype code, but it will take a while
to get this ready. Simpledrm will then support it.

I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
reliably. The fbdev console and Weston work automatically. Xorg requires
manual configuration of the device. Xorgs current modesetting driver does
not work with both, platform and PCI device, for the same physical
hardware. Once configured, X11 works. I looked into X11, but couldn't see
an easy way of fixing the problem. With the push towards Wayland+Xwayland
I expect the problem to become a non-issue soon. Additional testing has
been reported at [2].

One cosmetical issue is that simpledrm's device file is card0 and the
native driver's device file is card1. After simpledrm has been kicked out,
only card1 is left. This does not seem to be a practical problem however.

TODO/IDEAS:

	* provide deferred takeover
	* provide bootsplash DRM client
	* make simplekms usable with ARM-EFI fbs

v2:
	* rename to simpledrm, aperture helpers
	* reorganized patches
	* use hotplug helpers for removal (Daniel)
	* added DT match tables (Rob)
	* use shadow-plane helpers
	* lots of minor cleanups

[1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
[2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/

Thomas Zimmermann (10):
  drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
  drm/format-helper: Add blitter functions
  drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  drm/aperture: Add infrastructure for aperture ownership
  drm: Add simpledrm driver
  drm/simpledrm: Add fbdev emulation
  drm/simpledrm: Initialize framebuffer data from device-tree node
  drm/simpledrm: Acquire clocks from DT device node
  drm/simpledrm: Acquire regulators from DT device node
  drm/simpledrm: Acquire memory aperture for framebuffer

 Documentation/gpu/drm-internals.rst    |  12 +
 MAINTAINERS                            |   7 +
 drivers/gpu/drm/Kconfig                |   7 +
 drivers/gpu/drm/Makefile               |   1 +
 drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
 drivers/gpu/drm/drm_format_helper.c    |  96 ++-
 drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
 drivers/gpu/drm/tiny/Kconfig           |  17 +
 drivers/gpu/drm/tiny/Makefile          |   1 +
 drivers/gpu/drm/tiny/cirrus.c          |   2 +-
 drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
 include/drm/drm_aperture.h             |  96 +++
 include/drm/drm_fb_helper.h            |  56 +-
 include/drm/drm_format_helper.h        |  10 +-
 14 files changed, 1466 insertions(+), 60 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
 create mode 100644 include/drm/drm_aperture.h

--
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* [PATCH v2 01/10] drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann, Daniel Vetter

The memcpy's destination buffer might have a different pitch than the
source. Support different pitches as function argument.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c    | 9 +++++----
 drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +-
 drivers/gpu/drm/tiny/cirrus.c          | 2 +-
 include/drm/drm_format_helper.h        | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index c043ca364c86..8d5a683afea7 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(drm_fb_memcpy);
 /**
  * drm_fb_memcpy_dstclip - Copy clip buffer
  * @dst: Destination buffer (iomem)
+ * @dst_pitch: Number of bytes between two consecutive scanlines within dst
  * @vaddr: Source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
@@ -59,12 +60,12 @@ EXPORT_SYMBOL(drm_fb_memcpy);
  * This function applies clipping on dst, i.e. the destination is a
  * full (iomem) framebuffer but only the clip rect content is copied over.
  */
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
-			   struct drm_framebuffer *fb,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			   void *vaddr, struct drm_framebuffer *fb,
 			   struct drm_rect *clip)
 {
 	unsigned int cpp = fb->format->cpp[0];
-	unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
+	unsigned int offset = clip_offset(clip, dst_pitch, cpp);
 	size_t len = (clip->x2 - clip->x1) * cpp;
 	unsigned int y, lines = clip->y2 - clip->y1;
 
@@ -73,7 +74,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
 	for (y = 0; y < lines; y++) {
 		memcpy_toio(dst, vaddr, len);
 		vaddr += fb->pitches[0];
-		dst += fb->pitches[0];
+		dst += dst_pitch;
 	}
 }
 EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index cece3e57fb27..9d576240faed 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1554,7 +1554,7 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
 {
 	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
 
-	drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip);
+	drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip);
 
 	/* Always scanout image at VRAM offset 0 */
 	mgag200_set_startadd(mdev, (u32)0);
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index ad922c3ec681..ae5643b0a6f4 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -323,7 +323,7 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_
 		return -ENODEV;
 
 	if (cirrus->cpp == fb->format->cpp[0])
-		drm_fb_memcpy_dstclip(cirrus->vram,
+		drm_fb_memcpy_dstclip(cirrus->vram, fb->pitches[0],
 				      vmap, fb, rect);
 
 	else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2)
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 5f9e37032468..2b5036a5fbe7 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -11,7 +11,7 @@ struct drm_rect;
 
 void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
 		   struct drm_rect *clip);
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr,
 			   struct drm_framebuffer *fb,
 			   struct drm_rect *clip);
 void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 01/10] drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

The memcpy's destination buffer might have a different pitch than the
source. Support different pitches as function argument.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c    | 9 +++++----
 drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +-
 drivers/gpu/drm/tiny/cirrus.c          | 2 +-
 include/drm/drm_format_helper.h        | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index c043ca364c86..8d5a683afea7 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(drm_fb_memcpy);
 /**
  * drm_fb_memcpy_dstclip - Copy clip buffer
  * @dst: Destination buffer (iomem)
+ * @dst_pitch: Number of bytes between two consecutive scanlines within dst
  * @vaddr: Source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
@@ -59,12 +60,12 @@ EXPORT_SYMBOL(drm_fb_memcpy);
  * This function applies clipping on dst, i.e. the destination is a
  * full (iomem) framebuffer but only the clip rect content is copied over.
  */
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
-			   struct drm_framebuffer *fb,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			   void *vaddr, struct drm_framebuffer *fb,
 			   struct drm_rect *clip)
 {
 	unsigned int cpp = fb->format->cpp[0];
-	unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
+	unsigned int offset = clip_offset(clip, dst_pitch, cpp);
 	size_t len = (clip->x2 - clip->x1) * cpp;
 	unsigned int y, lines = clip->y2 - clip->y1;
 
@@ -73,7 +74,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
 	for (y = 0; y < lines; y++) {
 		memcpy_toio(dst, vaddr, len);
 		vaddr += fb->pitches[0];
-		dst += fb->pitches[0];
+		dst += dst_pitch;
 	}
 }
 EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index cece3e57fb27..9d576240faed 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1554,7 +1554,7 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
 {
 	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
 
-	drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip);
+	drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip);
 
 	/* Always scanout image at VRAM offset 0 */
 	mgag200_set_startadd(mdev, (u32)0);
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index ad922c3ec681..ae5643b0a6f4 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -323,7 +323,7 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_
 		return -ENODEV;
 
 	if (cirrus->cpp == fb->format->cpp[0])
-		drm_fb_memcpy_dstclip(cirrus->vram,
+		drm_fb_memcpy_dstclip(cirrus->vram, fb->pitches[0],
 				      vmap, fb, rect);
 
 	else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2)
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 5f9e37032468..2b5036a5fbe7 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -11,7 +11,7 @@ struct drm_rect;
 
 void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
 		   struct drm_rect *clip);
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr,
 			   struct drm_framebuffer *fb,
 			   struct drm_rect *clip);
 void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 01/10] drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

The memcpy's destination buffer might have a different pitch than the
source. Support different pitches as function argument.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c    | 9 +++++----
 drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +-
 drivers/gpu/drm/tiny/cirrus.c          | 2 +-
 include/drm/drm_format_helper.h        | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index c043ca364c86..8d5a683afea7 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(drm_fb_memcpy);
 /**
  * drm_fb_memcpy_dstclip - Copy clip buffer
  * @dst: Destination buffer (iomem)
+ * @dst_pitch: Number of bytes between two consecutive scanlines within dst
  * @vaddr: Source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
@@ -59,12 +60,12 @@ EXPORT_SYMBOL(drm_fb_memcpy);
  * This function applies clipping on dst, i.e. the destination is a
  * full (iomem) framebuffer but only the clip rect content is copied over.
  */
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
-			   struct drm_framebuffer *fb,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			   void *vaddr, struct drm_framebuffer *fb,
 			   struct drm_rect *clip)
 {
 	unsigned int cpp = fb->format->cpp[0];
-	unsigned int offset = clip_offset(clip, fb->pitches[0], cpp);
+	unsigned int offset = clip_offset(clip, dst_pitch, cpp);
 	size_t len = (clip->x2 - clip->x1) * cpp;
 	unsigned int y, lines = clip->y2 - clip->y1;
 
@@ -73,7 +74,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
 	for (y = 0; y < lines; y++) {
 		memcpy_toio(dst, vaddr, len);
 		vaddr += fb->pitches[0];
-		dst += fb->pitches[0];
+		dst += dst_pitch;
 	}
 }
 EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index cece3e57fb27..9d576240faed 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1554,7 +1554,7 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
 {
 	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
 
-	drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip);
+	drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip);
 
 	/* Always scanout image at VRAM offset 0 */
 	mgag200_set_startadd(mdev, (u32)0);
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index ad922c3ec681..ae5643b0a6f4 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -323,7 +323,7 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_
 		return -ENODEV;
 
 	if (cirrus->cpp == fb->format->cpp[0])
-		drm_fb_memcpy_dstclip(cirrus->vram,
+		drm_fb_memcpy_dstclip(cirrus->vram, fb->pitches[0],
 				      vmap, fb, rect);
 
 	else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2)
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 5f9e37032468..2b5036a5fbe7 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -11,7 +11,7 @@ struct drm_rect;
 
 void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
 		   struct drm_rect *clip);
-void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr,
+void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr,
 			   struct drm_framebuffer *fb,
 			   struct drm_rect *clip);
 void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb,
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 02/10] drm/format-helper: Add blitter functions
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann, Daniel Vetter

The blitter functions copy a framebuffer to I/O memory using one of
the existing conversion functions.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c | 87 +++++++++++++++++++++++++++++
 include/drm/drm_format_helper.h     |  8 +++
 2 files changed, 95 insertions(+)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 8d5a683afea7..0e885cd34107 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -344,3 +344,90 @@ void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
 
+/**
+ * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ * @clip:	Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory. If the
+ * formats of the display and the framebuffer mismatch, the blit function
+ * will attempt to convert between them.
+ *
+ * Use drm_fb_blit_dstclip() to copy the full framebuffer.
+ *
+ * Returns:
+ * 0 on success, or
+ * -EINVAL if the color-format conversion failed, or
+ * a negative error code otherwise.
+ */
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *clip)
+{
+	uint32_t fb_format = fb->format->format;
+
+	/* treat alpha channel like filler bits */
+	if (fb_format == DRM_FORMAT_ARGB8888)
+		fb_format = DRM_FORMAT_XRGB8888;
+	if (dst_format == DRM_FORMAT_ARGB8888)
+		dst_format = DRM_FORMAT_XRGB8888;
+
+	if (dst_format == fb_format) {
+		drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip);
+		return 0;
+
+	} else if (dst_format == DRM_FORMAT_RGB565) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch,
+							  vmap, fb, clip,
+							  false);
+			return 0;
+		}
+	} else if (dst_format == DRM_FORMAT_RGB888) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch,
+							  vmap, fb, clip);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
+
+/**
+ * drm_fb_blit_dstclip - Copy framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ *
+ * This function copies a full framebuffer to display memory. If the formats
+ * of the display and the framebuffer mismatch, the copy function will
+ * attempt to convert between them.
+ *
+ * See drm_fb_blit_rect_dstclip() for more inforamtion.
+ *
+ * Returns:
+ * 0 on success, or a negative error code otherwise.
+ */
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb)
+{
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = fb->width,
+		.y1 = 0,
+		.y2 = fb->height,
+	};
+	return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb,
+					&fullscreen);
+}
+EXPORT_SYMBOL(drm_fb_blit_dstclip);
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 2b5036a5fbe7..4e0258a61311 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -28,4 +28,12 @@ void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch
 void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 			      struct drm_rect *clip);
 
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *rect);
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb);
+
 #endif /* __LINUX_DRM_FORMAT_HELPER_H */
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 02/10] drm/format-helper: Add blitter functions
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

The blitter functions copy a framebuffer to I/O memory using one of
the existing conversion functions.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c | 87 +++++++++++++++++++++++++++++
 include/drm/drm_format_helper.h     |  8 +++
 2 files changed, 95 insertions(+)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 8d5a683afea7..0e885cd34107 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -344,3 +344,90 @@ void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
 
+/**
+ * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ * @clip:	Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory. If the
+ * formats of the display and the framebuffer mismatch, the blit function
+ * will attempt to convert between them.
+ *
+ * Use drm_fb_blit_dstclip() to copy the full framebuffer.
+ *
+ * Returns:
+ * 0 on success, or
+ * -EINVAL if the color-format conversion failed, or
+ * a negative error code otherwise.
+ */
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *clip)
+{
+	uint32_t fb_format = fb->format->format;
+
+	/* treat alpha channel like filler bits */
+	if (fb_format == DRM_FORMAT_ARGB8888)
+		fb_format = DRM_FORMAT_XRGB8888;
+	if (dst_format == DRM_FORMAT_ARGB8888)
+		dst_format = DRM_FORMAT_XRGB8888;
+
+	if (dst_format == fb_format) {
+		drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip);
+		return 0;
+
+	} else if (dst_format == DRM_FORMAT_RGB565) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch,
+							  vmap, fb, clip,
+							  false);
+			return 0;
+		}
+	} else if (dst_format == DRM_FORMAT_RGB888) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch,
+							  vmap, fb, clip);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
+
+/**
+ * drm_fb_blit_dstclip - Copy framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ *
+ * This function copies a full framebuffer to display memory. If the formats
+ * of the display and the framebuffer mismatch, the copy function will
+ * attempt to convert between them.
+ *
+ * See drm_fb_blit_rect_dstclip() for more inforamtion.
+ *
+ * Returns:
+ * 0 on success, or a negative error code otherwise.
+ */
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb)
+{
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = fb->width,
+		.y1 = 0,
+		.y2 = fb->height,
+	};
+	return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb,
+					&fullscreen);
+}
+EXPORT_SYMBOL(drm_fb_blit_dstclip);
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 2b5036a5fbe7..4e0258a61311 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -28,4 +28,12 @@ void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch
 void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 			      struct drm_rect *clip);
 
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *rect);
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb);
+
 #endif /* __LINUX_DRM_FORMAT_HELPER_H */
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 02/10] drm/format-helper: Add blitter functions
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

The blitter functions copy a framebuffer to I/O memory using one of
the existing conversion functions.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/drm_format_helper.c | 87 +++++++++++++++++++++++++++++
 include/drm/drm_format_helper.h     |  8 +++
 2 files changed, 95 insertions(+)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 8d5a683afea7..0e885cd34107 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -344,3 +344,90 @@ void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
 
+/**
+ * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ * @clip:	Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory. If the
+ * formats of the display and the framebuffer mismatch, the blit function
+ * will attempt to convert between them.
+ *
+ * Use drm_fb_blit_dstclip() to copy the full framebuffer.
+ *
+ * Returns:
+ * 0 on success, or
+ * -EINVAL if the color-format conversion failed, or
+ * a negative error code otherwise.
+ */
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *clip)
+{
+	uint32_t fb_format = fb->format->format;
+
+	/* treat alpha channel like filler bits */
+	if (fb_format == DRM_FORMAT_ARGB8888)
+		fb_format = DRM_FORMAT_XRGB8888;
+	if (dst_format == DRM_FORMAT_ARGB8888)
+		dst_format = DRM_FORMAT_XRGB8888;
+
+	if (dst_format == fb_format) {
+		drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip);
+		return 0;
+
+	} else if (dst_format == DRM_FORMAT_RGB565) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch,
+							  vmap, fb, clip,
+							  false);
+			return 0;
+		}
+	} else if (dst_format == DRM_FORMAT_RGB888) {
+		if (fb_format == DRM_FORMAT_XRGB8888) {
+			drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch,
+							  vmap, fb, clip);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
+
+/**
+ * drm_fb_blit_dstclip - Copy framebuffer to display memory
+ * @dst:	The display memory to copy to
+ * @dst_pitch:	Number of bytes between two consecutive scanlines within dst
+ * @dst_format:	FOURCC code of the display's color format
+ * @vmap:	The framebuffer memory to copy from
+ * @fb:		The framebuffer to copy from
+ *
+ * This function copies a full framebuffer to display memory. If the formats
+ * of the display and the framebuffer mismatch, the copy function will
+ * attempt to convert between them.
+ *
+ * See drm_fb_blit_rect_dstclip() for more inforamtion.
+ *
+ * Returns:
+ * 0 on success, or a negative error code otherwise.
+ */
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb)
+{
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = fb->width,
+		.y1 = 0,
+		.y2 = fb->height,
+	};
+	return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb,
+					&fullscreen);
+}
+EXPORT_SYMBOL(drm_fb_blit_dstclip);
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 2b5036a5fbe7..4e0258a61311 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -28,4 +28,12 @@ void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch
 void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 			      struct drm_rect *clip);
 
+int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			     uint32_t dst_format, void *vmap,
+			     struct drm_framebuffer *fb,
+			     struct drm_rect *rect);
+int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch,
+			uint32_t dst_format, void *vmap,
+			struct drm_framebuffer *fb);
+
 #endif /* __LINUX_DRM_FORMAT_HELPER_H */
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

Fbdev's helpers for handling conflicting framebuffers are related to
framebuffer apertures, not console emulation. Therefore move them into a
drm_aperture.h, which will contain the interfaces for the new aperture
helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |  6 +++
 include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
 include/drm/drm_fb_helper.h         | 56 ++-------------------------
 3 files changed, 69 insertions(+), 53 deletions(-)
 create mode 100644 include/drm/drm_aperture.h

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 12272b168580..4c7642d2ca34 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
 kernel log at initialization time and passes it to userspace through the
 DRM_IOCTL_VERSION ioctl.
 
+Managing Ownership of the Framebuffer Aperture
+----------------------------------------------
+
+.. kernel-doc:: include/drm/drm_aperture.h
+   :internal:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
new file mode 100644
index 000000000000..13766efe9517
--- /dev/null
+++ b/include/drm/drm_aperture.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef _DRM_APERTURE_H_
+#define _DRM_APERTURE_H_
+
+#include <linux/fb.h>
+#include <linux/vgaarb.h>
+
+/**
+ * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
+ * @a: memory range, users of which are to be removed
+ * @name: requesting driver name
+ * @primary: also kick vga16fb if present
+ *
+ * This function removes framebuffer devices (initialized by firmware/bootloader)
+ * which use memory range described by @a. If @a is NULL all such devices are
+ * removed.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
+					      const char *name, bool primary)
+{
+#if IS_REACHABLE(CONFIG_FB)
+	return remove_conflicting_framebuffers(a, name, primary);
+#else
+	return 0;
+#endif
+}
+
+/**
+ * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
+ *                                                     framebuffers for PCI devices
+ * @pdev: PCI device
+ * @name: requesting driver name
+ *
+ * This function removes framebuffer devices (eg. initialized by firmware)
+ * using memory range configured for any of @pdev's memory bars.
+ *
+ * The function assumes that PCI device with shadowed ROM drives a primary
+ * display and so kicks out vga16fb.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
+						  const char *name)
+{
+	int ret = 0;
+
+	/*
+	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
+	 * otherwise the vga fbdev driver falls over.
+	 */
+#if IS_REACHABLE(CONFIG_FB)
+	ret = remove_conflicting_pci_framebuffers(pdev, name);
+#endif
+	if (ret == 0)
+		ret = vga_remove_vgacon(pdev);
+	return ret;
+}
+
+#endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 3b273f9ca39a..d06a3942fddb 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,13 +30,13 @@
 #ifndef DRM_FB_HELPER_H
 #define DRM_FB_HELPER_H
 
-struct drm_fb_helper;
-
+#include <drm/drm_aperture.h>
 #include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <linux/kgdb.h>
-#include <linux/vgaarb.h>
+
+struct drm_fb_helper;
 
 enum mode_set_atomic {
 	LEAVE_ATOMIC_MODE_SET,
@@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
 
 #endif
 
-/**
- * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
- * @a: memory range, users of which are to be removed
- * @name: requesting driver name
- * @primary: also kick vga16fb if present
- *
- * This function removes framebuffer devices (initialized by firmware/bootloader)
- * which use memory range described by @a. If @a is NULL all such devices are
- * removed.
- */
-static inline int
-drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
-					      const char *name, bool primary)
-{
-#if IS_REACHABLE(CONFIG_FB)
-	return remove_conflicting_framebuffers(a, name, primary);
-#else
-	return 0;
-#endif
-}
-
-/**
- * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
- * @pdev: PCI device
- * @name: requesting driver name
- *
- * This function removes framebuffer devices (eg. initialized by firmware)
- * using memory range configured for any of @pdev's memory bars.
- *
- * The function assumes that PCI device with shadowed ROM drives a primary
- * display and so kicks out vga16fb.
- */
-static inline int
-drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
-						  const char *name)
-{
-	int ret = 0;
-
-	/*
-	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-	 * otherwise the vga fbdev driver falls over.
-	 */
-#if IS_REACHABLE(CONFIG_FB)
-	ret = remove_conflicting_pci_framebuffers(pdev, name);
-#endif
-	if (ret == 0)
-		ret = vga_remove_vgacon(pdev);
-	return ret;
-}
-
 #endif
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Fbdev's helpers for handling conflicting framebuffers are related to
framebuffer apertures, not console emulation. Therefore move them into a
drm_aperture.h, which will contain the interfaces for the new aperture
helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |  6 +++
 include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
 include/drm/drm_fb_helper.h         | 56 ++-------------------------
 3 files changed, 69 insertions(+), 53 deletions(-)
 create mode 100644 include/drm/drm_aperture.h

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 12272b168580..4c7642d2ca34 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
 kernel log at initialization time and passes it to userspace through the
 DRM_IOCTL_VERSION ioctl.
 
+Managing Ownership of the Framebuffer Aperture
+----------------------------------------------
+
+.. kernel-doc:: include/drm/drm_aperture.h
+   :internal:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
new file mode 100644
index 000000000000..13766efe9517
--- /dev/null
+++ b/include/drm/drm_aperture.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef _DRM_APERTURE_H_
+#define _DRM_APERTURE_H_
+
+#include <linux/fb.h>
+#include <linux/vgaarb.h>
+
+/**
+ * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
+ * @a: memory range, users of which are to be removed
+ * @name: requesting driver name
+ * @primary: also kick vga16fb if present
+ *
+ * This function removes framebuffer devices (initialized by firmware/bootloader)
+ * which use memory range described by @a. If @a is NULL all such devices are
+ * removed.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
+					      const char *name, bool primary)
+{
+#if IS_REACHABLE(CONFIG_FB)
+	return remove_conflicting_framebuffers(a, name, primary);
+#else
+	return 0;
+#endif
+}
+
+/**
+ * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
+ *                                                     framebuffers for PCI devices
+ * @pdev: PCI device
+ * @name: requesting driver name
+ *
+ * This function removes framebuffer devices (eg. initialized by firmware)
+ * using memory range configured for any of @pdev's memory bars.
+ *
+ * The function assumes that PCI device with shadowed ROM drives a primary
+ * display and so kicks out vga16fb.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
+						  const char *name)
+{
+	int ret = 0;
+
+	/*
+	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
+	 * otherwise the vga fbdev driver falls over.
+	 */
+#if IS_REACHABLE(CONFIG_FB)
+	ret = remove_conflicting_pci_framebuffers(pdev, name);
+#endif
+	if (ret == 0)
+		ret = vga_remove_vgacon(pdev);
+	return ret;
+}
+
+#endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 3b273f9ca39a..d06a3942fddb 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,13 +30,13 @@
 #ifndef DRM_FB_HELPER_H
 #define DRM_FB_HELPER_H
 
-struct drm_fb_helper;
-
+#include <drm/drm_aperture.h>
 #include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <linux/kgdb.h>
-#include <linux/vgaarb.h>
+
+struct drm_fb_helper;
 
 enum mode_set_atomic {
 	LEAVE_ATOMIC_MODE_SET,
@@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
 
 #endif
 
-/**
- * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
- * @a: memory range, users of which are to be removed
- * @name: requesting driver name
- * @primary: also kick vga16fb if present
- *
- * This function removes framebuffer devices (initialized by firmware/bootloader)
- * which use memory range described by @a. If @a is NULL all such devices are
- * removed.
- */
-static inline int
-drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
-					      const char *name, bool primary)
-{
-#if IS_REACHABLE(CONFIG_FB)
-	return remove_conflicting_framebuffers(a, name, primary);
-#else
-	return 0;
-#endif
-}
-
-/**
- * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
- * @pdev: PCI device
- * @name: requesting driver name
- *
- * This function removes framebuffer devices (eg. initialized by firmware)
- * using memory range configured for any of @pdev's memory bars.
- *
- * The function assumes that PCI device with shadowed ROM drives a primary
- * display and so kicks out vga16fb.
- */
-static inline int
-drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
-						  const char *name)
-{
-	int ret = 0;
-
-	/*
-	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-	 * otherwise the vga fbdev driver falls over.
-	 */
-#if IS_REACHABLE(CONFIG_FB)
-	ret = remove_conflicting_pci_framebuffers(pdev, name);
-#endif
-	if (ret == 0)
-		ret = vga_remove_vgacon(pdev);
-	return ret;
-}
-
 #endif
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Fbdev's helpers for handling conflicting framebuffers are related to
framebuffer apertures, not console emulation. Therefore move them into a
drm_aperture.h, which will contain the interfaces for the new aperture
helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |  6 +++
 include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
 include/drm/drm_fb_helper.h         | 56 ++-------------------------
 3 files changed, 69 insertions(+), 53 deletions(-)
 create mode 100644 include/drm/drm_aperture.h

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 12272b168580..4c7642d2ca34 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
 kernel log at initialization time and passes it to userspace through the
 DRM_IOCTL_VERSION ioctl.
 
+Managing Ownership of the Framebuffer Aperture
+----------------------------------------------
+
+.. kernel-doc:: include/drm/drm_aperture.h
+   :internal:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
new file mode 100644
index 000000000000..13766efe9517
--- /dev/null
+++ b/include/drm/drm_aperture.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef _DRM_APERTURE_H_
+#define _DRM_APERTURE_H_
+
+#include <linux/fb.h>
+#include <linux/vgaarb.h>
+
+/**
+ * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
+ * @a: memory range, users of which are to be removed
+ * @name: requesting driver name
+ * @primary: also kick vga16fb if present
+ *
+ * This function removes framebuffer devices (initialized by firmware/bootloader)
+ * which use memory range described by @a. If @a is NULL all such devices are
+ * removed.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
+					      const char *name, bool primary)
+{
+#if IS_REACHABLE(CONFIG_FB)
+	return remove_conflicting_framebuffers(a, name, primary);
+#else
+	return 0;
+#endif
+}
+
+/**
+ * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
+ *                                                     framebuffers for PCI devices
+ * @pdev: PCI device
+ * @name: requesting driver name
+ *
+ * This function removes framebuffer devices (eg. initialized by firmware)
+ * using memory range configured for any of @pdev's memory bars.
+ *
+ * The function assumes that PCI device with shadowed ROM drives a primary
+ * display and so kicks out vga16fb.
+ */
+static inline int
+drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
+						  const char *name)
+{
+	int ret = 0;
+
+	/*
+	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
+	 * otherwise the vga fbdev driver falls over.
+	 */
+#if IS_REACHABLE(CONFIG_FB)
+	ret = remove_conflicting_pci_framebuffers(pdev, name);
+#endif
+	if (ret == 0)
+		ret = vga_remove_vgacon(pdev);
+	return ret;
+}
+
+#endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 3b273f9ca39a..d06a3942fddb 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,13 +30,13 @@
 #ifndef DRM_FB_HELPER_H
 #define DRM_FB_HELPER_H
 
-struct drm_fb_helper;
-
+#include <drm/drm_aperture.h>
 #include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <linux/kgdb.h>
-#include <linux/vgaarb.h>
+
+struct drm_fb_helper;
 
 enum mode_set_atomic {
 	LEAVE_ATOMIC_MODE_SET,
@@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
 
 #endif
 
-/**
- * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
- * @a: memory range, users of which are to be removed
- * @name: requesting driver name
- * @primary: also kick vga16fb if present
- *
- * This function removes framebuffer devices (initialized by firmware/bootloader)
- * which use memory range described by @a. If @a is NULL all such devices are
- * removed.
- */
-static inline int
-drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
-					      const char *name, bool primary)
-{
-#if IS_REACHABLE(CONFIG_FB)
-	return remove_conflicting_framebuffers(a, name, primary);
-#else
-	return 0;
-#endif
-}
-
-/**
- * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
- * @pdev: PCI device
- * @name: requesting driver name
- *
- * This function removes framebuffer devices (eg. initialized by firmware)
- * using memory range configured for any of @pdev's memory bars.
- *
- * The function assumes that PCI device with shadowed ROM drives a primary
- * display and so kicks out vga16fb.
- */
-static inline int
-drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
-						  const char *name)
-{
-	int ret = 0;
-
-	/*
-	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-	 * otherwise the vga fbdev driver falls over.
-	 */
-#if IS_REACHABLE(CONFIG_FB)
-	ret = remove_conflicting_pci_framebuffers(pdev, name);
-#endif
-	if (ret == 0)
-		ret = vga_remove_vgacon(pdev);
-	return ret;
-}
-
 #endif
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

Platform devices might operate on firmware framebuffers, such as VESA or
EFI. Before a native driver for the graphics hardware can take over the
device, it has to remove any platform driver that operates on the firmware
framebuffer. Aperture helpers provide the infrastructure for platform
drivers to acquire firmware framebuffers, and for native drivers to remove
them later on.

It works similar to the related fbdev mechanism. During initialization, the
platform driver acquires the firmware framebuffer's I/O memory and provides
a callback to be removed. The native driver later uses this information to
remove any platform driver for it's framebuffer I/O memory.

The aperture removal code is integrated into the existing code for removing
conflicting framebuffers, so native drivers use it automatically.

v2:
	* rename plaform helpers to aperture helpers
	* tie to device lifetime with devm_ functions
	* removed unsued remove() callback
	* rename kickout to detach
	* make struct drm_aperture private
	* rebase onto existing drm_aperture.h header file
	* use MIT license only for simplicity
	* documentation

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |   6 +
 drivers/gpu/drm/Kconfig             |   7 +
 drivers/gpu/drm/Makefile            |   1 +
 drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
 include/drm/drm_aperture.h          |  38 +++-
 5 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 4c7642d2ca34..06af044c882f 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
 Managing Ownership of the Framebuffer Aperture
 ----------------------------------------------
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :doc: overview
+
 .. kernel-doc:: include/drm/drm_aperture.h
    :internal:
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :export:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1461652921be..b9d3fb91d22d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -221,6 +221,13 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_APERTURE
+	bool
+	depends on DRM
+	help
+	  Controls ownership of graphics apertures. Required to
+	  synchronize with firmware-based drivers.
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5eb5bf7c16e3..c9ecb02df0f3 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_PCI) += drm_pci.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o
 obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
new file mode 100644
index 000000000000..4b02b5fed0a1
--- /dev/null
+++ b/drivers/gpu/drm/drm_aperture.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: MIT
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+
+/**
+ * DOC: overview
+ *
+ * A graphics device might be supported by different drivers, but only one
+ * driver can be active at any given time. Many systems load a generic
+ * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
+ * During later boot stages, they replace the generic driver with a dedicated,
+ * hardware-specific driver. To take over the device the dedicated driver
+ * first has to remove the generic driver. DRM aperture functions manage
+ * ownership of DRM framebuffer memory and hand-over between drivers.
+ *
+ * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
+ * at the top of their probe function. The function removes any generic
+ * driver that is currently associated with the given framebuffer memory.
+ * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
+ * example given below.
+ *
+ * .. code-block:: c
+ *
+ *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
+ *	{
+ *		struct apertures_struct *ap;
+ *		bool primary = false;
+ *		int ret;
+ *
+ *		ap = alloc_apertures(1);
+ *		if (!ap)
+ *			return -ENOMEM;
+ *
+ *		ap->ranges[0].base = pci_resource_start(pdev, 0);
+ *		ap->ranges[0].size = pci_resource_len(pdev, 0);
+ *
+ *	#ifdef CONFIG_X86
+ *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+ *	#endif
+ *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
+ *		kfree(ap);
+ *
+ *		return ret;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = remove_conflicting_framebuffers(pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
+ * and let it detect the framebuffer apertures automatically.
+ *
+ * .. code-block:: c
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * Drivers that are susceptible to being removed be other drivers, such as
+ * generic EFI or VESA drivers, have to register themselves as owners of their
+ * given framebuffer memory. Ownership of the framebuffer memory is achived
+ * by calling devm_aperture_acquire(). On success, the driver is the owner
+ * of the framebuffer range. The function fails if the framebuffer is already
+ * by another driver. See below for an example.
+ *
+ * .. code-block:: c
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = ...
+ *	};
+ *
+ *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
+ *	{
+ *		resource_size_t start, len;
+ *		struct drm_aperture *ap;
+ *
+ *		base = pci_resource_start(pdev, 0);
+ *		size = pci_resource_len(pdev, 0);
+ *
+ *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
+ *		if (IS_ERR(ap))
+ *			return PTR_ERR(ap);
+ *
+ *		return 0;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		struct drm_device *dev;
+ *		int ret;
+ *
+ *		// ... Initialize the device...
+ *		dev = devm_drm_dev_alloc();
+ *		...
+ *
+ *		// ... and acquire ownership of the framebuffer.
+ *		ret = acquire_framebuffers(dev, pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * The generic driver is now subject to forced removal by other drivers. This
+ * is when the detach function in struct &drm_aperture_funcs comes into play.
+ * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
+ * for the registered framebuffer range, the DRM core calls struct
+ * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
+ * may not access the device's registers, framebuffer memory, ROM, etc after
+ * detach returned. If the driver supports hotplugging, detach can be treated
+ * like an unplug event.
+ *
+ * .. code-block:: c
+ *
+ *	static void detach_from_device(struct drm_device *dev,
+ *				       resource_size_t base,
+ *				       resource_size_t size)
+ *	{
+ *		// Signal unplug
+ *		drm_dev_unplug(dev);
+ *
+ *		// Maybe do other clean-up operations
+ *		...
+ *	}
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = detach_from_device,
+ *	};
+ */
+
+/**
+ * struct drm_aperture - Represents a DRM framebuffer aperture
+ *
+ * This structure has no public fields.
+ */
+struct drm_aperture {
+	struct drm_device *dev;
+	resource_size_t base;
+	resource_size_t size;
+
+	const struct drm_aperture_funcs *funcs;
+
+	struct list_head lh;
+};
+
+static LIST_HEAD(drm_apertures);
+
+static DEFINE_MUTEX(drm_apertures_lock);
+
+static bool overlap(resource_size_t base1, resource_size_t end1,
+		    resource_size_t base2, resource_size_t end2)
+{
+	return (base1 < end2) && (end1 > base2);
+}
+
+static void devm_aperture_acquire_release(void *data)
+{
+	struct drm_aperture *ap = data;
+	bool detached = !ap->dev;
+
+	if (!detached)
+		mutex_lock(&drm_apertures_lock);
+
+	list_del(&ap->lh);
+
+	if (!detached)
+		mutex_unlock(&drm_apertures_lock);
+}
+
+/**
+ * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
+ * @dev:	the DRM device to own the framebuffer memory
+ * @base:	the framebuffer's byte offset in physical memory
+ * @size:	the framebuffer size in bytes
+ * @funcs:	callback functions
+ *
+ * Installs the given device as the new owner. The function fails if the
+ * framebuffer range, or parts of it, is currently owned by another driver.
+ * To evict current owners, callers should use
+ * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
+ * function. Acquired apertures are released automatically if the underlying
+ * device goes away.
+ *
+ * Returns:
+ * An instance of struct &drm_aperture on success, or a pointer-encoded
+ * errno value otherwise.
+ */
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs)
+{
+	size_t end = base + size;
+	struct list_head *pos;
+	struct drm_aperture *ap;
+	int ret;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each(pos, &drm_apertures) {
+		ap = container_of(pos, struct drm_aperture, lh);
+		if (overlap(base, end, ap->base, ap->base + ap->size))
+			return ERR_PTR(-EBUSY);
+	}
+
+	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return ERR_PTR(-ENOMEM);
+
+	ap->dev = dev;
+	ap->base = base;
+	ap->size = size;
+	ap->funcs = funcs;
+	INIT_LIST_HEAD(&ap->lh);
+
+	list_add(&ap->lh, &drm_apertures);
+
+	mutex_unlock(&drm_apertures_lock);
+
+	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return ap;
+}
+EXPORT_SYMBOL(devm_aperture_acquire);
+
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+	resource_size_t end = base + size;
+	struct list_head *pos, *n;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each_safe(pos, n, &drm_apertures) {
+		struct drm_aperture *ap =
+			container_of(pos, struct drm_aperture, lh);
+		struct drm_device *dev = ap->dev;
+
+		if (!overlap(base, end, ap->base, ap->base + ap->size))
+			continue;
+
+		ap->dev = NULL; /* detach from device */
+		if (drm_WARN_ON(dev, !ap->funcs->detach))
+			continue;
+		ap->funcs->detach(dev, ap->base, ap->size);
+	}
+
+	mutex_unlock(&drm_apertures_lock);
+}
+EXPORT_SYMBOL(drm_aperture_detach_drivers);
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
index 13766efe9517..696cec75ef78 100644
--- a/include/drm/drm_aperture.h
+++ b/include/drm/drm_aperture.h
@@ -4,8 +4,30 @@
 #define _DRM_APERTURE_H_
 
 #include <linux/fb.h>
+#include <linux/pci.h>
 #include <linux/vgaarb.h>
 
+struct drm_aperture;
+struct drm_device;
+
+struct drm_aperture_funcs {
+	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
+};
+
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs);
+
+#if defined(CONFIG_DRM_APERTURE)
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
+#else
+static inline void
+drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+}
+#endif
+
 /**
  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
  * @a: memory range, users of which are to be removed
@@ -20,6 +42,11 @@ static inline int
 drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
 					      const char *name, bool primary)
 {
+	int i;
+
+	for (i = 0; i < a->count; ++i)
+		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
+
 #if IS_REACHABLE(CONFIG_FB)
 	return remove_conflicting_framebuffers(a, name, primary);
 #else
@@ -43,7 +70,16 @@ static inline int
 drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
 						  const char *name)
 {
-	int ret = 0;
+	resource_size_t base, size;
+	int bar, ret = 0;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+			continue;
+		base = pci_resource_start(pdev, bar);
+		size = pci_resource_len(pdev, bar);
+		drm_aperture_detach_drivers(base, size);
+	}
 
 	/*
 	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Platform devices might operate on firmware framebuffers, such as VESA or
EFI. Before a native driver for the graphics hardware can take over the
device, it has to remove any platform driver that operates on the firmware
framebuffer. Aperture helpers provide the infrastructure for platform
drivers to acquire firmware framebuffers, and for native drivers to remove
them later on.

It works similar to the related fbdev mechanism. During initialization, the
platform driver acquires the firmware framebuffer's I/O memory and provides
a callback to be removed. The native driver later uses this information to
remove any platform driver for it's framebuffer I/O memory.

The aperture removal code is integrated into the existing code for removing
conflicting framebuffers, so native drivers use it automatically.

v2:
	* rename plaform helpers to aperture helpers
	* tie to device lifetime with devm_ functions
	* removed unsued remove() callback
	* rename kickout to detach
	* make struct drm_aperture private
	* rebase onto existing drm_aperture.h header file
	* use MIT license only for simplicity
	* documentation

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |   6 +
 drivers/gpu/drm/Kconfig             |   7 +
 drivers/gpu/drm/Makefile            |   1 +
 drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
 include/drm/drm_aperture.h          |  38 +++-
 5 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 4c7642d2ca34..06af044c882f 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
 Managing Ownership of the Framebuffer Aperture
 ----------------------------------------------
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :doc: overview
+
 .. kernel-doc:: include/drm/drm_aperture.h
    :internal:
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :export:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1461652921be..b9d3fb91d22d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -221,6 +221,13 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_APERTURE
+	bool
+	depends on DRM
+	help
+	  Controls ownership of graphics apertures. Required to
+	  synchronize with firmware-based drivers.
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5eb5bf7c16e3..c9ecb02df0f3 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_PCI) += drm_pci.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o
 obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
new file mode 100644
index 000000000000..4b02b5fed0a1
--- /dev/null
+++ b/drivers/gpu/drm/drm_aperture.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: MIT
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+
+/**
+ * DOC: overview
+ *
+ * A graphics device might be supported by different drivers, but only one
+ * driver can be active at any given time. Many systems load a generic
+ * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
+ * During later boot stages, they replace the generic driver with a dedicated,
+ * hardware-specific driver. To take over the device the dedicated driver
+ * first has to remove the generic driver. DRM aperture functions manage
+ * ownership of DRM framebuffer memory and hand-over between drivers.
+ *
+ * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
+ * at the top of their probe function. The function removes any generic
+ * driver that is currently associated with the given framebuffer memory.
+ * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
+ * example given below.
+ *
+ * .. code-block:: c
+ *
+ *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
+ *	{
+ *		struct apertures_struct *ap;
+ *		bool primary = false;
+ *		int ret;
+ *
+ *		ap = alloc_apertures(1);
+ *		if (!ap)
+ *			return -ENOMEM;
+ *
+ *		ap->ranges[0].base = pci_resource_start(pdev, 0);
+ *		ap->ranges[0].size = pci_resource_len(pdev, 0);
+ *
+ *	#ifdef CONFIG_X86
+ *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+ *	#endif
+ *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
+ *		kfree(ap);
+ *
+ *		return ret;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = remove_conflicting_framebuffers(pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
+ * and let it detect the framebuffer apertures automatically.
+ *
+ * .. code-block:: c
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * Drivers that are susceptible to being removed be other drivers, such as
+ * generic EFI or VESA drivers, have to register themselves as owners of their
+ * given framebuffer memory. Ownership of the framebuffer memory is achived
+ * by calling devm_aperture_acquire(). On success, the driver is the owner
+ * of the framebuffer range. The function fails if the framebuffer is already
+ * by another driver. See below for an example.
+ *
+ * .. code-block:: c
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = ...
+ *	};
+ *
+ *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
+ *	{
+ *		resource_size_t start, len;
+ *		struct drm_aperture *ap;
+ *
+ *		base = pci_resource_start(pdev, 0);
+ *		size = pci_resource_len(pdev, 0);
+ *
+ *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
+ *		if (IS_ERR(ap))
+ *			return PTR_ERR(ap);
+ *
+ *		return 0;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		struct drm_device *dev;
+ *		int ret;
+ *
+ *		// ... Initialize the device...
+ *		dev = devm_drm_dev_alloc();
+ *		...
+ *
+ *		// ... and acquire ownership of the framebuffer.
+ *		ret = acquire_framebuffers(dev, pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * The generic driver is now subject to forced removal by other drivers. This
+ * is when the detach function in struct &drm_aperture_funcs comes into play.
+ * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
+ * for the registered framebuffer range, the DRM core calls struct
+ * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
+ * may not access the device's registers, framebuffer memory, ROM, etc after
+ * detach returned. If the driver supports hotplugging, detach can be treated
+ * like an unplug event.
+ *
+ * .. code-block:: c
+ *
+ *	static void detach_from_device(struct drm_device *dev,
+ *				       resource_size_t base,
+ *				       resource_size_t size)
+ *	{
+ *		// Signal unplug
+ *		drm_dev_unplug(dev);
+ *
+ *		// Maybe do other clean-up operations
+ *		...
+ *	}
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = detach_from_device,
+ *	};
+ */
+
+/**
+ * struct drm_aperture - Represents a DRM framebuffer aperture
+ *
+ * This structure has no public fields.
+ */
+struct drm_aperture {
+	struct drm_device *dev;
+	resource_size_t base;
+	resource_size_t size;
+
+	const struct drm_aperture_funcs *funcs;
+
+	struct list_head lh;
+};
+
+static LIST_HEAD(drm_apertures);
+
+static DEFINE_MUTEX(drm_apertures_lock);
+
+static bool overlap(resource_size_t base1, resource_size_t end1,
+		    resource_size_t base2, resource_size_t end2)
+{
+	return (base1 < end2) && (end1 > base2);
+}
+
+static void devm_aperture_acquire_release(void *data)
+{
+	struct drm_aperture *ap = data;
+	bool detached = !ap->dev;
+
+	if (!detached)
+		mutex_lock(&drm_apertures_lock);
+
+	list_del(&ap->lh);
+
+	if (!detached)
+		mutex_unlock(&drm_apertures_lock);
+}
+
+/**
+ * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
+ * @dev:	the DRM device to own the framebuffer memory
+ * @base:	the framebuffer's byte offset in physical memory
+ * @size:	the framebuffer size in bytes
+ * @funcs:	callback functions
+ *
+ * Installs the given device as the new owner. The function fails if the
+ * framebuffer range, or parts of it, is currently owned by another driver.
+ * To evict current owners, callers should use
+ * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
+ * function. Acquired apertures are released automatically if the underlying
+ * device goes away.
+ *
+ * Returns:
+ * An instance of struct &drm_aperture on success, or a pointer-encoded
+ * errno value otherwise.
+ */
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs)
+{
+	size_t end = base + size;
+	struct list_head *pos;
+	struct drm_aperture *ap;
+	int ret;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each(pos, &drm_apertures) {
+		ap = container_of(pos, struct drm_aperture, lh);
+		if (overlap(base, end, ap->base, ap->base + ap->size))
+			return ERR_PTR(-EBUSY);
+	}
+
+	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return ERR_PTR(-ENOMEM);
+
+	ap->dev = dev;
+	ap->base = base;
+	ap->size = size;
+	ap->funcs = funcs;
+	INIT_LIST_HEAD(&ap->lh);
+
+	list_add(&ap->lh, &drm_apertures);
+
+	mutex_unlock(&drm_apertures_lock);
+
+	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return ap;
+}
+EXPORT_SYMBOL(devm_aperture_acquire);
+
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+	resource_size_t end = base + size;
+	struct list_head *pos, *n;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each_safe(pos, n, &drm_apertures) {
+		struct drm_aperture *ap =
+			container_of(pos, struct drm_aperture, lh);
+		struct drm_device *dev = ap->dev;
+
+		if (!overlap(base, end, ap->base, ap->base + ap->size))
+			continue;
+
+		ap->dev = NULL; /* detach from device */
+		if (drm_WARN_ON(dev, !ap->funcs->detach))
+			continue;
+		ap->funcs->detach(dev, ap->base, ap->size);
+	}
+
+	mutex_unlock(&drm_apertures_lock);
+}
+EXPORT_SYMBOL(drm_aperture_detach_drivers);
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
index 13766efe9517..696cec75ef78 100644
--- a/include/drm/drm_aperture.h
+++ b/include/drm/drm_aperture.h
@@ -4,8 +4,30 @@
 #define _DRM_APERTURE_H_
 
 #include <linux/fb.h>
+#include <linux/pci.h>
 #include <linux/vgaarb.h>
 
+struct drm_aperture;
+struct drm_device;
+
+struct drm_aperture_funcs {
+	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
+};
+
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs);
+
+#if defined(CONFIG_DRM_APERTURE)
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
+#else
+static inline void
+drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+}
+#endif
+
 /**
  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
  * @a: memory range, users of which are to be removed
@@ -20,6 +42,11 @@ static inline int
 drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
 					      const char *name, bool primary)
 {
+	int i;
+
+	for (i = 0; i < a->count; ++i)
+		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
+
 #if IS_REACHABLE(CONFIG_FB)
 	return remove_conflicting_framebuffers(a, name, primary);
 #else
@@ -43,7 +70,16 @@ static inline int
 drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
 						  const char *name)
 {
-	int ret = 0;
+	resource_size_t base, size;
+	int bar, ret = 0;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+			continue;
+		base = pci_resource_start(pdev, bar);
+		size = pci_resource_len(pdev, bar);
+		drm_aperture_detach_drivers(base, size);
+	}
 
 	/*
 	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Platform devices might operate on firmware framebuffers, such as VESA or
EFI. Before a native driver for the graphics hardware can take over the
device, it has to remove any platform driver that operates on the firmware
framebuffer. Aperture helpers provide the infrastructure for platform
drivers to acquire firmware framebuffers, and for native drivers to remove
them later on.

It works similar to the related fbdev mechanism. During initialization, the
platform driver acquires the firmware framebuffer's I/O memory and provides
a callback to be removed. The native driver later uses this information to
remove any platform driver for it's framebuffer I/O memory.

The aperture removal code is integrated into the existing code for removing
conflicting framebuffers, so native drivers use it automatically.

v2:
	* rename plaform helpers to aperture helpers
	* tie to device lifetime with devm_ functions
	* removed unsued remove() callback
	* rename kickout to detach
	* make struct drm_aperture private
	* rebase onto existing drm_aperture.h header file
	* use MIT license only for simplicity
	* documentation

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 Documentation/gpu/drm-internals.rst |   6 +
 drivers/gpu/drm/Kconfig             |   7 +
 drivers/gpu/drm/Makefile            |   1 +
 drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
 include/drm/drm_aperture.h          |  38 +++-
 5 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_aperture.c

diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
index 4c7642d2ca34..06af044c882f 100644
--- a/Documentation/gpu/drm-internals.rst
+++ b/Documentation/gpu/drm-internals.rst
@@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
 Managing Ownership of the Framebuffer Aperture
 ----------------------------------------------
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :doc: overview
+
 .. kernel-doc:: include/drm/drm_aperture.h
    :internal:
 
+.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
+   :export:
+
 Device Instance and Driver Handling
 -----------------------------------
 
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1461652921be..b9d3fb91d22d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -221,6 +221,13 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_APERTURE
+	bool
+	depends on DRM
+	help
+	  Controls ownership of graphics apertures. Required to
+	  synchronize with firmware-based drivers.
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5eb5bf7c16e3..c9ecb02df0f3 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_PCI) += drm_pci.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o
 obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
new file mode 100644
index 000000000000..4b02b5fed0a1
--- /dev/null
+++ b/drivers/gpu/drm/drm_aperture.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: MIT
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+
+/**
+ * DOC: overview
+ *
+ * A graphics device might be supported by different drivers, but only one
+ * driver can be active at any given time. Many systems load a generic
+ * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
+ * During later boot stages, they replace the generic driver with a dedicated,
+ * hardware-specific driver. To take over the device the dedicated driver
+ * first has to remove the generic driver. DRM aperture functions manage
+ * ownership of DRM framebuffer memory and hand-over between drivers.
+ *
+ * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
+ * at the top of their probe function. The function removes any generic
+ * driver that is currently associated with the given framebuffer memory.
+ * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
+ * example given below.
+ *
+ * .. code-block:: c
+ *
+ *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
+ *	{
+ *		struct apertures_struct *ap;
+ *		bool primary = false;
+ *		int ret;
+ *
+ *		ap = alloc_apertures(1);
+ *		if (!ap)
+ *			return -ENOMEM;
+ *
+ *		ap->ranges[0].base = pci_resource_start(pdev, 0);
+ *		ap->ranges[0].size = pci_resource_len(pdev, 0);
+ *
+ *	#ifdef CONFIG_X86
+ *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+ *	#endif
+ *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
+ *		kfree(ap);
+ *
+ *		return ret;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = remove_conflicting_framebuffers(pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
+ * and let it detect the framebuffer apertures automatically.
+ *
+ * .. code-block:: c
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		int ret;
+ *
+ *		// Remove any generic drivers...
+ *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
+ *		if (ret)
+ *			return ret;
+ *
+ *		// ... and initialize the hardware.
+ *		...
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * Drivers that are susceptible to being removed be other drivers, such as
+ * generic EFI or VESA drivers, have to register themselves as owners of their
+ * given framebuffer memory. Ownership of the framebuffer memory is achived
+ * by calling devm_aperture_acquire(). On success, the driver is the owner
+ * of the framebuffer range. The function fails if the framebuffer is already
+ * by another driver. See below for an example.
+ *
+ * .. code-block:: c
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = ...
+ *	};
+ *
+ *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
+ *	{
+ *		resource_size_t start, len;
+ *		struct drm_aperture *ap;
+ *
+ *		base = pci_resource_start(pdev, 0);
+ *		size = pci_resource_len(pdev, 0);
+ *
+ *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
+ *		if (IS_ERR(ap))
+ *			return PTR_ERR(ap);
+ *
+ *		return 0;
+ *	}
+ *
+ *	static int probe(struct pci_dev *pdev)
+ *	{
+ *		struct drm_device *dev;
+ *		int ret;
+ *
+ *		// ... Initialize the device...
+ *		dev = devm_drm_dev_alloc();
+ *		...
+ *
+ *		// ... and acquire ownership of the framebuffer.
+ *		ret = acquire_framebuffers(dev, pdev);
+ *		if (ret)
+ *			return ret;
+ *
+ *		drm_dev_register();
+ *
+ *		return 0;
+ *	}
+ *
+ * The generic driver is now subject to forced removal by other drivers. This
+ * is when the detach function in struct &drm_aperture_funcs comes into play.
+ * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
+ * for the registered framebuffer range, the DRM core calls struct
+ * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
+ * may not access the device's registers, framebuffer memory, ROM, etc after
+ * detach returned. If the driver supports hotplugging, detach can be treated
+ * like an unplug event.
+ *
+ * .. code-block:: c
+ *
+ *	static void detach_from_device(struct drm_device *dev,
+ *				       resource_size_t base,
+ *				       resource_size_t size)
+ *	{
+ *		// Signal unplug
+ *		drm_dev_unplug(dev);
+ *
+ *		// Maybe do other clean-up operations
+ *		...
+ *	}
+ *
+ *	static struct drm_aperture_funcs ap_funcs = {
+ *		.detach = detach_from_device,
+ *	};
+ */
+
+/**
+ * struct drm_aperture - Represents a DRM framebuffer aperture
+ *
+ * This structure has no public fields.
+ */
+struct drm_aperture {
+	struct drm_device *dev;
+	resource_size_t base;
+	resource_size_t size;
+
+	const struct drm_aperture_funcs *funcs;
+
+	struct list_head lh;
+};
+
+static LIST_HEAD(drm_apertures);
+
+static DEFINE_MUTEX(drm_apertures_lock);
+
+static bool overlap(resource_size_t base1, resource_size_t end1,
+		    resource_size_t base2, resource_size_t end2)
+{
+	return (base1 < end2) && (end1 > base2);
+}
+
+static void devm_aperture_acquire_release(void *data)
+{
+	struct drm_aperture *ap = data;
+	bool detached = !ap->dev;
+
+	if (!detached)
+		mutex_lock(&drm_apertures_lock);
+
+	list_del(&ap->lh);
+
+	if (!detached)
+		mutex_unlock(&drm_apertures_lock);
+}
+
+/**
+ * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
+ * @dev:	the DRM device to own the framebuffer memory
+ * @base:	the framebuffer's byte offset in physical memory
+ * @size:	the framebuffer size in bytes
+ * @funcs:	callback functions
+ *
+ * Installs the given device as the new owner. The function fails if the
+ * framebuffer range, or parts of it, is currently owned by another driver.
+ * To evict current owners, callers should use
+ * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
+ * function. Acquired apertures are released automatically if the underlying
+ * device goes away.
+ *
+ * Returns:
+ * An instance of struct &drm_aperture on success, or a pointer-encoded
+ * errno value otherwise.
+ */
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs)
+{
+	size_t end = base + size;
+	struct list_head *pos;
+	struct drm_aperture *ap;
+	int ret;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each(pos, &drm_apertures) {
+		ap = container_of(pos, struct drm_aperture, lh);
+		if (overlap(base, end, ap->base, ap->base + ap->size))
+			return ERR_PTR(-EBUSY);
+	}
+
+	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return ERR_PTR(-ENOMEM);
+
+	ap->dev = dev;
+	ap->base = base;
+	ap->size = size;
+	ap->funcs = funcs;
+	INIT_LIST_HEAD(&ap->lh);
+
+	list_add(&ap->lh, &drm_apertures);
+
+	mutex_unlock(&drm_apertures_lock);
+
+	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return ap;
+}
+EXPORT_SYMBOL(devm_aperture_acquire);
+
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+	resource_size_t end = base + size;
+	struct list_head *pos, *n;
+
+	mutex_lock(&drm_apertures_lock);
+
+	list_for_each_safe(pos, n, &drm_apertures) {
+		struct drm_aperture *ap =
+			container_of(pos, struct drm_aperture, lh);
+		struct drm_device *dev = ap->dev;
+
+		if (!overlap(base, end, ap->base, ap->base + ap->size))
+			continue;
+
+		ap->dev = NULL; /* detach from device */
+		if (drm_WARN_ON(dev, !ap->funcs->detach))
+			continue;
+		ap->funcs->detach(dev, ap->base, ap->size);
+	}
+
+	mutex_unlock(&drm_apertures_lock);
+}
+EXPORT_SYMBOL(drm_aperture_detach_drivers);
diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
index 13766efe9517..696cec75ef78 100644
--- a/include/drm/drm_aperture.h
+++ b/include/drm/drm_aperture.h
@@ -4,8 +4,30 @@
 #define _DRM_APERTURE_H_
 
 #include <linux/fb.h>
+#include <linux/pci.h>
 #include <linux/vgaarb.h>
 
+struct drm_aperture;
+struct drm_device;
+
+struct drm_aperture_funcs {
+	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
+};
+
+struct drm_aperture *
+devm_aperture_acquire(struct drm_device *dev,
+		      resource_size_t base, resource_size_t size,
+		      const struct drm_aperture_funcs *funcs);
+
+#if defined(CONFIG_DRM_APERTURE)
+void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
+#else
+static inline void
+drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
+{
+}
+#endif
+
 /**
  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
  * @a: memory range, users of which are to be removed
@@ -20,6 +42,11 @@ static inline int
 drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
 					      const char *name, bool primary)
 {
+	int i;
+
+	for (i = 0; i < a->count; ++i)
+		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
+
 #if IS_REACHABLE(CONFIG_FB)
 	return remove_conflicting_framebuffers(a, name, primary);
 #else
@@ -43,7 +70,16 @@ static inline int
 drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
 						  const char *name)
 {
-	int ret = 0;
+	resource_size_t base, size;
+	int bar, ret = 0;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+			continue;
+		base = pci_resource_start(pdev, bar);
+		size = pci_resource_len(pdev, bar);
+		drm_aperture_detach_drivers(base, size);
+	}
 
 	/*
 	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 05/10] drm: Add simpledrm driver
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

The simpledrm driver is a DRM driver for simplefb framebuffers as
provided by the kernel's boot code. This driver enables basic
graphical output on many different graphics devices that are provided
by the platform (e.g., EFI, VESA, embedded framebuffers).

With the kernel's simplefb infrastructure, the kernel receives a
pre-configured framebuffer from the system (i.e., firmware, boot
loader). It creates a platform device to which simpledrm attaches.
The system's framebuffer consists of a memory range, size and format.
Based on these values, simpledrm creates a DRM devices. No actual
modesetting is possible.

v2:
	* rename driver to simpledrm
	* add dri-devel to MAINTAINERS entry
	* put native format first in primary-plane format list (Daniel)
	* inline simplekms_device_cleanup() (Daniel)
	* use helpers for shadow-buffered planes
	* fix whitespace errors

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 MAINTAINERS                      |   7 +
 drivers/gpu/drm/tiny/Kconfig     |  16 +
 drivers/gpu/drm/tiny/Makefile    |   1 +
 drivers/gpu/drm/tiny/simpledrm.c | 527 +++++++++++++++++++++++++++++++
 4 files changed, 551 insertions(+)
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3dc7b57be31d..e9d53daf8b58 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5744,6 +5744,13 @@ S:	Orphan / Obsolete
 F:	drivers/gpu/drm/savage/
 F:	include/uapi/drm/savage_drm.h
 
+DRM DRIVER FOR SIMPLE FRAMEBUFFERS
+M:	Thomas Zimmermann <tzimmermann@suse.de>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	drivers/gpu/drm/tiny/simplekms.c
+
 DRM DRIVER FOR SIS VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/sis/
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 9bbaa1a69050..d46f95d9196d 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -38,6 +38,22 @@ config DRM_GM12U320
 	 This is a KMS driver for projectors which use the GM12U320 chipset
 	 for video transfer over USB2/3, such as the Acer C120 mini projector.
 
+config DRM_SIMPLEDRM
+	tristate "Simple framebuffer driver"
+	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  DRM driver for simple platform-provided framebuffers.
+
+	  This driver assumes that the display hardware has been initialized
+	  by the firmware or bootloader before the kernel boots. Scanout
+	  buffer, size, and display format must be provided via device tree,
+	  UEFI, VESA, etc.
+
+	  On x86 and compatible, you should also select CONFIG_X86_SYSFB to
+	  use UEFI and VESA framebuffers.
+
 config TINYDRM_HX8357D
 	tristate "DRM support for HX8357D display panels"
 	depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index bef6780bdd6f..9cc847e756da 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_DRM_ARCPGU)		+= arcpgu.o
 obj-$(CONFIG_DRM_CIRRUS_QEMU)		+= cirrus.o
 obj-$(CONFIG_DRM_GM12U320)		+= gm12u320.o
+obj-$(CONFIG_DRM_SIMPLEDRM)		+= simpledrm.o
 obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
new file mode 100644
index 000000000000..0422c549b97a
--- /dev/null
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define DRIVER_NAME	"simpledrm"
+#define DRIVER_DESC	"DRM driver for simple-framebuffer platform devices"
+#define DRIVER_DATE	"20200625"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+/*
+ * Assume a monitor resolution of 96 dpi to
+ * get a somewhat reasonable screen size.
+ */
+#define RES_MM(d)	\
+	(((d) * 254ul) / (96ul * 10ul))
+
+#define SIMPLEDRM_MODE(hd, vd)	\
+	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
+
+/*
+ * Helpers for simplefb
+ */
+
+static int
+simplefb_get_validated_int(struct drm_device *dev, const char *name,
+			   uint32_t value)
+{
+	if (value > INT_MAX) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return (int)value;
+}
+
+static int
+simplefb_get_validated_int0(struct drm_device *dev, const char *name,
+			    uint32_t value)
+{
+	if (!value) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return simplefb_get_validated_int(dev, name, value);
+}
+
+static const struct drm_format_info *
+simplefb_get_validated_format(struct drm_device *dev, const char *format_name)
+{
+	static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+	const struct simplefb_format *fmt = formats;
+	const struct simplefb_format *end = fmt + ARRAY_SIZE(formats);
+
+	if (!format_name) {
+		drm_err(dev, "simplefb: missing framebuffer format\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	while (fmt < end) {
+		if (!strcmp(format_name, fmt->name))
+			return drm_format_info(fmt->fourcc);
+		++fmt;
+	}
+
+	drm_err(dev, "simplefb: unknown framebuffer format %s\n",
+		format_name);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int
+simplefb_get_width_pd(struct drm_device *dev,
+		      const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "width", pd->width);
+}
+
+static int
+simplefb_get_height_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "height", pd->height);
+}
+
+static int
+simplefb_get_stride_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int(dev, "stride", pd->stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_format(dev, pd->format);
+}
+
+/*
+ * Simple Framebuffer device
+ */
+
+struct simpledrm_device {
+	struct drm_device dev;
+	struct platform_device *pdev;
+
+	/* simplefb settings */
+	struct drm_display_mode mode;
+	const struct drm_format_info *format;
+	unsigned int pitch;
+
+	/* memory management */
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	/* modesetting */
+	uint32_t formats[8];
+	size_t nformats;
+	struct drm_connector connector;
+	struct drm_simple_display_pipe pipe;
+};
+
+static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct simpledrm_device, dev);
+}
+
+/*
+ *  Simplefb settings
+ */
+
+static struct drm_display_mode simpledrm_mode(unsigned int width,
+					      unsigned int height)
+{
+	struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
+
+	mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay;
+	drm_mode_set_name(&mode);
+
+	return mode;
+}
+
+static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
+{
+	int width, height, stride;
+	const struct drm_format_info *format;
+	struct drm_format_name_buf buf;
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+
+	if (pd) {
+		width = simplefb_get_width_pd(dev, pd);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_pd(dev, pd);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_pd(dev, pd);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_pd(dev, pd);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
+	} else {
+		drm_err(dev, "no simplefb configuration found\n");
+		return -ENODEV;
+	}
+
+	sdev->mode = simpledrm_mode(width, height);
+	sdev->format = format;
+	sdev->pitch = stride;
+
+	drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n",
+		    DRM_MODE_ARG(&sdev->mode));
+	drm_dbg_kms(dev,
+		    "framebuffer format=\"%s\", size=%dx%d, stride=%d byte\n",
+		    drm_get_format_name(format->format, &buf), width,
+		    height, stride);
+
+	return 0;
+}
+
+/*
+ * Memory management
+ */
+
+static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
+{
+	struct platform_device *pdev = sdev->pdev;
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -EINVAL;
+
+	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
+				      resource_size(mem));
+	if (!screen_base)
+		return -ENOMEM;
+
+	sdev->mem = mem;
+	sdev->screen_base = screen_base;
+
+	return 0;
+}
+
+/*
+ * Modesetting
+ */
+
+/*
+ * Support all formats of simplefb and maybe more; in order
+ * of preference. The display's update function will do any
+ * conversion necessary.
+ *
+ * TODO: Add blit helpers for remaining formats and uncomment
+ *       constants.
+ */
+static const uint32_t simpledrm_default_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	//DRM_FORMAT_XRGB1555,
+	//DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB888,
+	//DRM_FORMAT_XRGB2101010,
+	//DRM_FORMAT_ARGB2101010,
+};
+
+static const uint64_t simpledrm_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, &sdev->mode);
+	if (!mode)
+		return 0;
+
+	if (mode->name[0] == '\0')
+		drm_mode_set_name(mode);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	if (mode->width_mm)
+		connector->display_info.width_mm = mode->width_mm;
+	if (mode->height_mm)
+		connector->display_info.height_mm = mode->height_mm;
+
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
+	.get_modes = simpledrm_connector_helper_get_modes,
+};
+
+static const struct drm_connector_funcs simpledrm_connector_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int
+simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+				    const struct drm_display_mode *mode)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+
+	if (mode->hdisplay != sdev->mode.hdisplay &&
+	    mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_SIZE;
+	else if (mode->hdisplay != sdev->mode.hdisplay)
+		return MODE_ONE_WIDTH;
+	else if (mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_HEIGHT;
+
+	return MODE_OK;
+}
+
+static void
+simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				     struct drm_crtc_state *crtc_state,
+				     struct drm_plane_state *plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	struct drm_framebuffer *fb = plane_state->fb;
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+
+	if (!fb)
+		return;
+
+	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
+			    sdev->format->format, vmap, fb);
+}
+
+static void
+simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *old_plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_plane_state *plane_state = pipe->plane.state;
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_rect clip;
+
+	if (!fb)
+		return;
+
+	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
+		return;
+
+	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
+				 sdev->format->format, vmap, fb, &clip);
+}
+
+static const struct drm_simple_display_pipe_funcs
+simpledrm_simple_display_pipe_funcs = {
+	.mode_valid = simpledrm_simple_display_pipe_mode_valid,
+	.enable = simpledrm_simple_display_pipe_enable,
+	.update = simpledrm_simple_display_pipe_update,
+	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
+};
+
+static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev,
+						size_t *nformats_out)
+{
+	struct drm_device *dev = &sdev->dev;
+	size_t i;
+
+	if (sdev->nformats)
+		goto out; /* don't rebuild list on recurring calls */
+
+	/* native format goes first */
+	sdev->formats[0] = sdev->format->format;
+	sdev->nformats = 1;
+
+	/* default formats go second */
+	for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) {
+		if (simpledrm_default_formats[i] == sdev->format->format)
+			continue; /* native format already went first */
+		sdev->formats[sdev->nformats] = simpledrm_default_formats[i];
+		sdev->nformats++;
+	}
+
+	/*
+	 * TODO: The simpledrm driver converts framebuffers to the native
+	 * format when copying them to device memory. If there are more
+	 * formats listed than supported by the driver, the native format
+	 * is not supported by the conversion helpers. Therefore *only*
+	 * support the native format and add a conversion helper ASAP.
+	 */
+	if (drm_WARN_ONCE(dev, i != sdev->nformats,
+			  "format conversion helpers required for %p4cc",
+			  &sdev->format->format)) {
+		sdev->nformats = 1;
+	}
+
+out:
+	*nformats_out = sdev->nformats;
+	return sdev->formats;
+}
+
+static int simpledrm_device_init_modeset(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct drm_display_mode *mode = &sdev->mode;
+	struct drm_connector *connector = &sdev->connector;
+	struct drm_simple_display_pipe *pipe = &sdev->pipe;
+	const uint32_t *formats;
+	size_t nformats;
+	int ret;
+
+	ret = drmm_mode_config_init(dev);
+	if (ret)
+		return ret;
+
+	dev->mode_config.min_width = mode->hdisplay;
+	dev->mode_config.max_width = mode->hdisplay;
+	dev->mode_config.min_height = mode->vdisplay;
+	dev->mode_config.max_height = mode->vdisplay;
+	dev->mode_config.prefer_shadow = true;
+	dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8;
+	dev->mode_config.funcs = &simpledrm_mode_config_funcs;
+
+	ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret)
+		return ret;
+	drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
+
+	formats = simpledrm_device_formats(sdev, &nformats);
+
+	ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs,
+					   formats, nformats, simpledrm_format_modifiers,
+					   connector);
+	if (ret)
+		return ret;
+
+	drm_mode_config_reset(dev);
+
+	return 0;
+}
+
+/*
+ * Init / Cleanup
+ */
+
+static struct simpledrm_device *
+simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	int ret;
+
+	sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device,
+				  dev);
+	if (IS_ERR(sdev))
+		return ERR_CAST(sdev);
+	sdev->pdev = pdev;
+
+	ret = simpledrm_device_init_fb(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_mm(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_modeset(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return sdev;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(simpledrm_fops);
+
+static struct drm_driver simpledrm_driver = {
+	DRM_GEM_SHMEM_DRIVER_OPS,
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= DRIVER_DATE,
+	.major			= DRIVER_MAJOR,
+	.minor			= DRIVER_MINOR,
+	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+	.fops			= &simpledrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int simpledrm_probe(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	struct drm_device *dev;
+	int ret;
+
+	sdev = simpledrm_device_create(&simpledrm_driver, pdev);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+	dev = &sdev->dev;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int simpledrm_remove(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
+	struct drm_device *dev = &sdev->dev;
+
+	drm_dev_unregister(dev);
+
+	return 0;
+}
+
+static struct platform_driver simpledrm_platform_driver = {
+	.driver = {
+		.name = "simple-framebuffer", /* connect to sysfb */
+	},
+	.probe = simpledrm_probe,
+	.remove = simpledrm_remove,
+};
+
+module_platform_driver(simpledrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 05/10] drm: Add simpledrm driver
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

The simpledrm driver is a DRM driver for simplefb framebuffers as
provided by the kernel's boot code. This driver enables basic
graphical output on many different graphics devices that are provided
by the platform (e.g., EFI, VESA, embedded framebuffers).

With the kernel's simplefb infrastructure, the kernel receives a
pre-configured framebuffer from the system (i.e., firmware, boot
loader). It creates a platform device to which simpledrm attaches.
The system's framebuffer consists of a memory range, size and format.
Based on these values, simpledrm creates a DRM devices. No actual
modesetting is possible.

v2:
	* rename driver to simpledrm
	* add dri-devel to MAINTAINERS entry
	* put native format first in primary-plane format list (Daniel)
	* inline simplekms_device_cleanup() (Daniel)
	* use helpers for shadow-buffered planes
	* fix whitespace errors

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 MAINTAINERS                      |   7 +
 drivers/gpu/drm/tiny/Kconfig     |  16 +
 drivers/gpu/drm/tiny/Makefile    |   1 +
 drivers/gpu/drm/tiny/simpledrm.c | 527 +++++++++++++++++++++++++++++++
 4 files changed, 551 insertions(+)
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3dc7b57be31d..e9d53daf8b58 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5744,6 +5744,13 @@ S:	Orphan / Obsolete
 F:	drivers/gpu/drm/savage/
 F:	include/uapi/drm/savage_drm.h
 
+DRM DRIVER FOR SIMPLE FRAMEBUFFERS
+M:	Thomas Zimmermann <tzimmermann@suse.de>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	drivers/gpu/drm/tiny/simplekms.c
+
 DRM DRIVER FOR SIS VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/sis/
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 9bbaa1a69050..d46f95d9196d 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -38,6 +38,22 @@ config DRM_GM12U320
 	 This is a KMS driver for projectors which use the GM12U320 chipset
 	 for video transfer over USB2/3, such as the Acer C120 mini projector.
 
+config DRM_SIMPLEDRM
+	tristate "Simple framebuffer driver"
+	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  DRM driver for simple platform-provided framebuffers.
+
+	  This driver assumes that the display hardware has been initialized
+	  by the firmware or bootloader before the kernel boots. Scanout
+	  buffer, size, and display format must be provided via device tree,
+	  UEFI, VESA, etc.
+
+	  On x86 and compatible, you should also select CONFIG_X86_SYSFB to
+	  use UEFI and VESA framebuffers.
+
 config TINYDRM_HX8357D
 	tristate "DRM support for HX8357D display panels"
 	depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index bef6780bdd6f..9cc847e756da 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_DRM_ARCPGU)		+= arcpgu.o
 obj-$(CONFIG_DRM_CIRRUS_QEMU)		+= cirrus.o
 obj-$(CONFIG_DRM_GM12U320)		+= gm12u320.o
+obj-$(CONFIG_DRM_SIMPLEDRM)		+= simpledrm.o
 obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
new file mode 100644
index 000000000000..0422c549b97a
--- /dev/null
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define DRIVER_NAME	"simpledrm"
+#define DRIVER_DESC	"DRM driver for simple-framebuffer platform devices"
+#define DRIVER_DATE	"20200625"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+/*
+ * Assume a monitor resolution of 96 dpi to
+ * get a somewhat reasonable screen size.
+ */
+#define RES_MM(d)	\
+	(((d) * 254ul) / (96ul * 10ul))
+
+#define SIMPLEDRM_MODE(hd, vd)	\
+	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
+
+/*
+ * Helpers for simplefb
+ */
+
+static int
+simplefb_get_validated_int(struct drm_device *dev, const char *name,
+			   uint32_t value)
+{
+	if (value > INT_MAX) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return (int)value;
+}
+
+static int
+simplefb_get_validated_int0(struct drm_device *dev, const char *name,
+			    uint32_t value)
+{
+	if (!value) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return simplefb_get_validated_int(dev, name, value);
+}
+
+static const struct drm_format_info *
+simplefb_get_validated_format(struct drm_device *dev, const char *format_name)
+{
+	static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+	const struct simplefb_format *fmt = formats;
+	const struct simplefb_format *end = fmt + ARRAY_SIZE(formats);
+
+	if (!format_name) {
+		drm_err(dev, "simplefb: missing framebuffer format\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	while (fmt < end) {
+		if (!strcmp(format_name, fmt->name))
+			return drm_format_info(fmt->fourcc);
+		++fmt;
+	}
+
+	drm_err(dev, "simplefb: unknown framebuffer format %s\n",
+		format_name);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int
+simplefb_get_width_pd(struct drm_device *dev,
+		      const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "width", pd->width);
+}
+
+static int
+simplefb_get_height_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "height", pd->height);
+}
+
+static int
+simplefb_get_stride_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int(dev, "stride", pd->stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_format(dev, pd->format);
+}
+
+/*
+ * Simple Framebuffer device
+ */
+
+struct simpledrm_device {
+	struct drm_device dev;
+	struct platform_device *pdev;
+
+	/* simplefb settings */
+	struct drm_display_mode mode;
+	const struct drm_format_info *format;
+	unsigned int pitch;
+
+	/* memory management */
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	/* modesetting */
+	uint32_t formats[8];
+	size_t nformats;
+	struct drm_connector connector;
+	struct drm_simple_display_pipe pipe;
+};
+
+static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct simpledrm_device, dev);
+}
+
+/*
+ *  Simplefb settings
+ */
+
+static struct drm_display_mode simpledrm_mode(unsigned int width,
+					      unsigned int height)
+{
+	struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
+
+	mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay;
+	drm_mode_set_name(&mode);
+
+	return mode;
+}
+
+static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
+{
+	int width, height, stride;
+	const struct drm_format_info *format;
+	struct drm_format_name_buf buf;
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+
+	if (pd) {
+		width = simplefb_get_width_pd(dev, pd);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_pd(dev, pd);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_pd(dev, pd);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_pd(dev, pd);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
+	} else {
+		drm_err(dev, "no simplefb configuration found\n");
+		return -ENODEV;
+	}
+
+	sdev->mode = simpledrm_mode(width, height);
+	sdev->format = format;
+	sdev->pitch = stride;
+
+	drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n",
+		    DRM_MODE_ARG(&sdev->mode));
+	drm_dbg_kms(dev,
+		    "framebuffer format=\"%s\", size=%dx%d, stride=%d byte\n",
+		    drm_get_format_name(format->format, &buf), width,
+		    height, stride);
+
+	return 0;
+}
+
+/*
+ * Memory management
+ */
+
+static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
+{
+	struct platform_device *pdev = sdev->pdev;
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -EINVAL;
+
+	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
+				      resource_size(mem));
+	if (!screen_base)
+		return -ENOMEM;
+
+	sdev->mem = mem;
+	sdev->screen_base = screen_base;
+
+	return 0;
+}
+
+/*
+ * Modesetting
+ */
+
+/*
+ * Support all formats of simplefb and maybe more; in order
+ * of preference. The display's update function will do any
+ * conversion necessary.
+ *
+ * TODO: Add blit helpers for remaining formats and uncomment
+ *       constants.
+ */
+static const uint32_t simpledrm_default_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	//DRM_FORMAT_XRGB1555,
+	//DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB888,
+	//DRM_FORMAT_XRGB2101010,
+	//DRM_FORMAT_ARGB2101010,
+};
+
+static const uint64_t simpledrm_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, &sdev->mode);
+	if (!mode)
+		return 0;
+
+	if (mode->name[0] == '\0')
+		drm_mode_set_name(mode);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	if (mode->width_mm)
+		connector->display_info.width_mm = mode->width_mm;
+	if (mode->height_mm)
+		connector->display_info.height_mm = mode->height_mm;
+
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
+	.get_modes = simpledrm_connector_helper_get_modes,
+};
+
+static const struct drm_connector_funcs simpledrm_connector_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int
+simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+				    const struct drm_display_mode *mode)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+
+	if (mode->hdisplay != sdev->mode.hdisplay &&
+	    mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_SIZE;
+	else if (mode->hdisplay != sdev->mode.hdisplay)
+		return MODE_ONE_WIDTH;
+	else if (mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_HEIGHT;
+
+	return MODE_OK;
+}
+
+static void
+simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				     struct drm_crtc_state *crtc_state,
+				     struct drm_plane_state *plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	struct drm_framebuffer *fb = plane_state->fb;
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+
+	if (!fb)
+		return;
+
+	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
+			    sdev->format->format, vmap, fb);
+}
+
+static void
+simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *old_plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_plane_state *plane_state = pipe->plane.state;
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_rect clip;
+
+	if (!fb)
+		return;
+
+	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
+		return;
+
+	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
+				 sdev->format->format, vmap, fb, &clip);
+}
+
+static const struct drm_simple_display_pipe_funcs
+simpledrm_simple_display_pipe_funcs = {
+	.mode_valid = simpledrm_simple_display_pipe_mode_valid,
+	.enable = simpledrm_simple_display_pipe_enable,
+	.update = simpledrm_simple_display_pipe_update,
+	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
+};
+
+static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev,
+						size_t *nformats_out)
+{
+	struct drm_device *dev = &sdev->dev;
+	size_t i;
+
+	if (sdev->nformats)
+		goto out; /* don't rebuild list on recurring calls */
+
+	/* native format goes first */
+	sdev->formats[0] = sdev->format->format;
+	sdev->nformats = 1;
+
+	/* default formats go second */
+	for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) {
+		if (simpledrm_default_formats[i] == sdev->format->format)
+			continue; /* native format already went first */
+		sdev->formats[sdev->nformats] = simpledrm_default_formats[i];
+		sdev->nformats++;
+	}
+
+	/*
+	 * TODO: The simpledrm driver converts framebuffers to the native
+	 * format when copying them to device memory. If there are more
+	 * formats listed than supported by the driver, the native format
+	 * is not supported by the conversion helpers. Therefore *only*
+	 * support the native format and add a conversion helper ASAP.
+	 */
+	if (drm_WARN_ONCE(dev, i != sdev->nformats,
+			  "format conversion helpers required for %p4cc",
+			  &sdev->format->format)) {
+		sdev->nformats = 1;
+	}
+
+out:
+	*nformats_out = sdev->nformats;
+	return sdev->formats;
+}
+
+static int simpledrm_device_init_modeset(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct drm_display_mode *mode = &sdev->mode;
+	struct drm_connector *connector = &sdev->connector;
+	struct drm_simple_display_pipe *pipe = &sdev->pipe;
+	const uint32_t *formats;
+	size_t nformats;
+	int ret;
+
+	ret = drmm_mode_config_init(dev);
+	if (ret)
+		return ret;
+
+	dev->mode_config.min_width = mode->hdisplay;
+	dev->mode_config.max_width = mode->hdisplay;
+	dev->mode_config.min_height = mode->vdisplay;
+	dev->mode_config.max_height = mode->vdisplay;
+	dev->mode_config.prefer_shadow = true;
+	dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8;
+	dev->mode_config.funcs = &simpledrm_mode_config_funcs;
+
+	ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret)
+		return ret;
+	drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
+
+	formats = simpledrm_device_formats(sdev, &nformats);
+
+	ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs,
+					   formats, nformats, simpledrm_format_modifiers,
+					   connector);
+	if (ret)
+		return ret;
+
+	drm_mode_config_reset(dev);
+
+	return 0;
+}
+
+/*
+ * Init / Cleanup
+ */
+
+static struct simpledrm_device *
+simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	int ret;
+
+	sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device,
+				  dev);
+	if (IS_ERR(sdev))
+		return ERR_CAST(sdev);
+	sdev->pdev = pdev;
+
+	ret = simpledrm_device_init_fb(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_mm(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_modeset(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return sdev;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(simpledrm_fops);
+
+static struct drm_driver simpledrm_driver = {
+	DRM_GEM_SHMEM_DRIVER_OPS,
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= DRIVER_DATE,
+	.major			= DRIVER_MAJOR,
+	.minor			= DRIVER_MINOR,
+	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+	.fops			= &simpledrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int simpledrm_probe(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	struct drm_device *dev;
+	int ret;
+
+	sdev = simpledrm_device_create(&simpledrm_driver, pdev);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+	dev = &sdev->dev;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int simpledrm_remove(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
+	struct drm_device *dev = &sdev->dev;
+
+	drm_dev_unregister(dev);
+
+	return 0;
+}
+
+static struct platform_driver simpledrm_platform_driver = {
+	.driver = {
+		.name = "simple-framebuffer", /* connect to sysfb */
+	},
+	.probe = simpledrm_probe,
+	.remove = simpledrm_remove,
+};
+
+module_platform_driver(simpledrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 05/10] drm: Add simpledrm driver
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

The simpledrm driver is a DRM driver for simplefb framebuffers as
provided by the kernel's boot code. This driver enables basic
graphical output on many different graphics devices that are provided
by the platform (e.g., EFI, VESA, embedded framebuffers).

With the kernel's simplefb infrastructure, the kernel receives a
pre-configured framebuffer from the system (i.e., firmware, boot
loader). It creates a platform device to which simpledrm attaches.
The system's framebuffer consists of a memory range, size and format.
Based on these values, simpledrm creates a DRM devices. No actual
modesetting is possible.

v2:
	* rename driver to simpledrm
	* add dri-devel to MAINTAINERS entry
	* put native format first in primary-plane format list (Daniel)
	* inline simplekms_device_cleanup() (Daniel)
	* use helpers for shadow-buffered planes
	* fix whitespace errors

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 MAINTAINERS                      |   7 +
 drivers/gpu/drm/tiny/Kconfig     |  16 +
 drivers/gpu/drm/tiny/Makefile    |   1 +
 drivers/gpu/drm/tiny/simpledrm.c | 527 +++++++++++++++++++++++++++++++
 4 files changed, 551 insertions(+)
 create mode 100644 drivers/gpu/drm/tiny/simpledrm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3dc7b57be31d..e9d53daf8b58 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5744,6 +5744,13 @@ S:	Orphan / Obsolete
 F:	drivers/gpu/drm/savage/
 F:	include/uapi/drm/savage_drm.h
 
+DRM DRIVER FOR SIMPLE FRAMEBUFFERS
+M:	Thomas Zimmermann <tzimmermann@suse.de>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	drivers/gpu/drm/tiny/simplekms.c
+
 DRM DRIVER FOR SIS VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/sis/
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 9bbaa1a69050..d46f95d9196d 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -38,6 +38,22 @@ config DRM_GM12U320
 	 This is a KMS driver for projectors which use the GM12U320 chipset
 	 for video transfer over USB2/3, such as the Acer C120 mini projector.
 
+config DRM_SIMPLEDRM
+	tristate "Simple framebuffer driver"
+	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  DRM driver for simple platform-provided framebuffers.
+
+	  This driver assumes that the display hardware has been initialized
+	  by the firmware or bootloader before the kernel boots. Scanout
+	  buffer, size, and display format must be provided via device tree,
+	  UEFI, VESA, etc.
+
+	  On x86 and compatible, you should also select CONFIG_X86_SYSFB to
+	  use UEFI and VESA framebuffers.
+
 config TINYDRM_HX8357D
 	tristate "DRM support for HX8357D display panels"
 	depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index bef6780bdd6f..9cc847e756da 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_DRM_ARCPGU)		+= arcpgu.o
 obj-$(CONFIG_DRM_CIRRUS_QEMU)		+= cirrus.o
 obj-$(CONFIG_DRM_GM12U320)		+= gm12u320.o
+obj-$(CONFIG_DRM_SIMPLEDRM)		+= simpledrm.o
 obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
new file mode 100644
index 000000000000..0422c549b97a
--- /dev/null
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#define DRIVER_NAME	"simpledrm"
+#define DRIVER_DESC	"DRM driver for simple-framebuffer platform devices"
+#define DRIVER_DATE	"20200625"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+/*
+ * Assume a monitor resolution of 96 dpi to
+ * get a somewhat reasonable screen size.
+ */
+#define RES_MM(d)	\
+	(((d) * 254ul) / (96ul * 10ul))
+
+#define SIMPLEDRM_MODE(hd, vd)	\
+	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
+
+/*
+ * Helpers for simplefb
+ */
+
+static int
+simplefb_get_validated_int(struct drm_device *dev, const char *name,
+			   uint32_t value)
+{
+	if (value > INT_MAX) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return (int)value;
+}
+
+static int
+simplefb_get_validated_int0(struct drm_device *dev, const char *name,
+			    uint32_t value)
+{
+	if (!value) {
+		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",
+			name, value);
+		return -EINVAL;
+	}
+	return simplefb_get_validated_int(dev, name, value);
+}
+
+static const struct drm_format_info *
+simplefb_get_validated_format(struct drm_device *dev, const char *format_name)
+{
+	static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+	const struct simplefb_format *fmt = formats;
+	const struct simplefb_format *end = fmt + ARRAY_SIZE(formats);
+
+	if (!format_name) {
+		drm_err(dev, "simplefb: missing framebuffer format\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	while (fmt < end) {
+		if (!strcmp(format_name, fmt->name))
+			return drm_format_info(fmt->fourcc);
+		++fmt;
+	}
+
+	drm_err(dev, "simplefb: unknown framebuffer format %s\n",
+		format_name);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int
+simplefb_get_width_pd(struct drm_device *dev,
+		      const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "width", pd->width);
+}
+
+static int
+simplefb_get_height_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int0(dev, "height", pd->height);
+}
+
+static int
+simplefb_get_stride_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_int(dev, "stride", pd->stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_pd(struct drm_device *dev,
+		       const struct simplefb_platform_data *pd)
+{
+	return simplefb_get_validated_format(dev, pd->format);
+}
+
+/*
+ * Simple Framebuffer device
+ */
+
+struct simpledrm_device {
+	struct drm_device dev;
+	struct platform_device *pdev;
+
+	/* simplefb settings */
+	struct drm_display_mode mode;
+	const struct drm_format_info *format;
+	unsigned int pitch;
+
+	/* memory management */
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	/* modesetting */
+	uint32_t formats[8];
+	size_t nformats;
+	struct drm_connector connector;
+	struct drm_simple_display_pipe pipe;
+};
+
+static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct simpledrm_device, dev);
+}
+
+/*
+ *  Simplefb settings
+ */
+
+static struct drm_display_mode simpledrm_mode(unsigned int width,
+					      unsigned int height)
+{
+	struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
+
+	mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay;
+	drm_mode_set_name(&mode);
+
+	return mode;
+}
+
+static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
+{
+	int width, height, stride;
+	const struct drm_format_info *format;
+	struct drm_format_name_buf buf;
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+
+	if (pd) {
+		width = simplefb_get_width_pd(dev, pd);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_pd(dev, pd);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_pd(dev, pd);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_pd(dev, pd);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
+	} else {
+		drm_err(dev, "no simplefb configuration found\n");
+		return -ENODEV;
+	}
+
+	sdev->mode = simpledrm_mode(width, height);
+	sdev->format = format;
+	sdev->pitch = stride;
+
+	drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n",
+		    DRM_MODE_ARG(&sdev->mode));
+	drm_dbg_kms(dev,
+		    "framebuffer format=\"%s\", size=%dx%d, stride=%d byte\n",
+		    drm_get_format_name(format->format, &buf), width,
+		    height, stride);
+
+	return 0;
+}
+
+/*
+ * Memory management
+ */
+
+static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
+{
+	struct platform_device *pdev = sdev->pdev;
+	struct resource *mem;
+	void __iomem *screen_base;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -EINVAL;
+
+	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
+				      resource_size(mem));
+	if (!screen_base)
+		return -ENOMEM;
+
+	sdev->mem = mem;
+	sdev->screen_base = screen_base;
+
+	return 0;
+}
+
+/*
+ * Modesetting
+ */
+
+/*
+ * Support all formats of simplefb and maybe more; in order
+ * of preference. The display's update function will do any
+ * conversion necessary.
+ *
+ * TODO: Add blit helpers for remaining formats and uncomment
+ *       constants.
+ */
+static const uint32_t simpledrm_default_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGB565,
+	//DRM_FORMAT_XRGB1555,
+	//DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB888,
+	//DRM_FORMAT_XRGB2101010,
+	//DRM_FORMAT_ARGB2101010,
+};
+
+static const uint64_t simpledrm_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, &sdev->mode);
+	if (!mode)
+		return 0;
+
+	if (mode->name[0] == '\0')
+		drm_mode_set_name(mode);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	if (mode->width_mm)
+		connector->display_info.width_mm = mode->width_mm;
+	if (mode->height_mm)
+		connector->display_info.height_mm = mode->height_mm;
+
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
+	.get_modes = simpledrm_connector_helper_get_modes,
+};
+
+static const struct drm_connector_funcs simpledrm_connector_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int
+simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+				    const struct drm_display_mode *mode)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+
+	if (mode->hdisplay != sdev->mode.hdisplay &&
+	    mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_SIZE;
+	else if (mode->hdisplay != sdev->mode.hdisplay)
+		return MODE_ONE_WIDTH;
+	else if (mode->vdisplay != sdev->mode.vdisplay)
+		return MODE_ONE_HEIGHT;
+
+	return MODE_OK;
+}
+
+static void
+simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				     struct drm_crtc_state *crtc_state,
+				     struct drm_plane_state *plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	struct drm_framebuffer *fb = plane_state->fb;
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+
+	if (!fb)
+		return;
+
+	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
+			    sdev->format->format, vmap, fb);
+}
+
+static void
+simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *old_plane_state)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->connector->dev);
+	struct drm_plane_state *plane_state = pipe->plane.state;
+	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_rect clip;
+
+	if (!fb)
+		return;
+
+	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
+		return;
+
+	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
+				 sdev->format->format, vmap, fb, &clip);
+}
+
+static const struct drm_simple_display_pipe_funcs
+simpledrm_simple_display_pipe_funcs = {
+	.mode_valid = simpledrm_simple_display_pipe_mode_valid,
+	.enable = simpledrm_simple_display_pipe_enable,
+	.update = simpledrm_simple_display_pipe_update,
+	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
+};
+
+static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev,
+						size_t *nformats_out)
+{
+	struct drm_device *dev = &sdev->dev;
+	size_t i;
+
+	if (sdev->nformats)
+		goto out; /* don't rebuild list on recurring calls */
+
+	/* native format goes first */
+	sdev->formats[0] = sdev->format->format;
+	sdev->nformats = 1;
+
+	/* default formats go second */
+	for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) {
+		if (simpledrm_default_formats[i] == sdev->format->format)
+			continue; /* native format already went first */
+		sdev->formats[sdev->nformats] = simpledrm_default_formats[i];
+		sdev->nformats++;
+	}
+
+	/*
+	 * TODO: The simpledrm driver converts framebuffers to the native
+	 * format when copying them to device memory. If there are more
+	 * formats listed than supported by the driver, the native format
+	 * is not supported by the conversion helpers. Therefore *only*
+	 * support the native format and add a conversion helper ASAP.
+	 */
+	if (drm_WARN_ONCE(dev, i != sdev->nformats,
+			  "format conversion helpers required for %p4cc",
+			  &sdev->format->format)) {
+		sdev->nformats = 1;
+	}
+
+out:
+	*nformats_out = sdev->nformats;
+	return sdev->formats;
+}
+
+static int simpledrm_device_init_modeset(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct drm_display_mode *mode = &sdev->mode;
+	struct drm_connector *connector = &sdev->connector;
+	struct drm_simple_display_pipe *pipe = &sdev->pipe;
+	const uint32_t *formats;
+	size_t nformats;
+	int ret;
+
+	ret = drmm_mode_config_init(dev);
+	if (ret)
+		return ret;
+
+	dev->mode_config.min_width = mode->hdisplay;
+	dev->mode_config.max_width = mode->hdisplay;
+	dev->mode_config.min_height = mode->vdisplay;
+	dev->mode_config.max_height = mode->vdisplay;
+	dev->mode_config.prefer_shadow = true;
+	dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8;
+	dev->mode_config.funcs = &simpledrm_mode_config_funcs;
+
+	ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret)
+		return ret;
+	drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
+
+	formats = simpledrm_device_formats(sdev, &nformats);
+
+	ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs,
+					   formats, nformats, simpledrm_format_modifiers,
+					   connector);
+	if (ret)
+		return ret;
+
+	drm_mode_config_reset(dev);
+
+	return 0;
+}
+
+/*
+ * Init / Cleanup
+ */
+
+static struct simpledrm_device *
+simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	int ret;
+
+	sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device,
+				  dev);
+	if (IS_ERR(sdev))
+		return ERR_CAST(sdev);
+	sdev->pdev = pdev;
+
+	ret = simpledrm_device_init_fb(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_mm(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_modeset(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return sdev;
+}
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(simpledrm_fops);
+
+static struct drm_driver simpledrm_driver = {
+	DRM_GEM_SHMEM_DRIVER_OPS,
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= DRIVER_DATE,
+	.major			= DRIVER_MAJOR,
+	.minor			= DRIVER_MINOR,
+	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+	.fops			= &simpledrm_fops,
+};
+
+/*
+ * Platform driver
+ */
+
+static int simpledrm_probe(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev;
+	struct drm_device *dev;
+	int ret;
+
+	sdev = simpledrm_device_create(&simpledrm_driver, pdev);
+	if (IS_ERR(sdev))
+		return PTR_ERR(sdev);
+	dev = &sdev->dev;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int simpledrm_remove(struct platform_device *pdev)
+{
+	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
+	struct drm_device *dev = &sdev->dev;
+
+	drm_dev_unregister(dev);
+
+	return 0;
+}
+
+static struct platform_driver simpledrm_platform_driver = {
+	.driver = {
+		.name = "simple-framebuffer", /* connect to sysfb */
+	},
+	.probe = simpledrm_probe,
+	.remove = simpledrm_remove,
+};
+
+module_platform_driver(simpledrm_platform_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 06/10] drm/simpledrm: Add fbdev emulation
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann, Daniel Vetter

This displays a console on simpledrm's framebuffer. The default
framebuffer format is being used.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 0422c549b97a..4f0d4ec0b432 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -8,6 +8,7 @@
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_format_helper.h>
 #include <drm/drm_gem_atomic_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -500,6 +501,8 @@ static int simpledrm_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	drm_fbdev_generic_setup(dev, 0);
+
 	return 0;
 }
 
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 06/10] drm/simpledrm: Add fbdev emulation
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

This displays a console on simpledrm's framebuffer. The default
framebuffer format is being used.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 0422c549b97a..4f0d4ec0b432 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -8,6 +8,7 @@
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_format_helper.h>
 #include <drm/drm_gem_atomic_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -500,6 +501,8 @@ static int simpledrm_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	drm_fbdev_generic_setup(dev, 0);
+
 	return 0;
 }
 
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 06/10] drm/simpledrm: Add fbdev emulation
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: Daniel Vetter, virtualization, Thomas Zimmermann, dri-devel, linux-doc

This displays a console on simpledrm's framebuffer. The default
framebuffer format is being used.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 0422c549b97a..4f0d4ec0b432 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -8,6 +8,7 @@
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_format_helper.h>
 #include <drm/drm_gem_atomic_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -500,6 +501,8 @@ static int simpledrm_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	drm_fbdev_generic_setup(dev, 0);
+
 	return 0;
 }
 
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 07/10] drm/simpledrm: Initialize framebuffer data from device-tree node
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

A firmware framebuffer might also be specified via device-tree files. If
no device platform data is given, try the DT device node.

v2:
	* add Device Tree match table
	* clean-up parser wrappers

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 89 ++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 4f0d4ec0b432..c9cef2b50de6 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -114,6 +114,74 @@ simplefb_get_format_pd(struct drm_device *dev,
 	return simplefb_get_validated_format(dev, pd->format);
 }
 
+static int
+simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node,
+		     const char *name, u32 *value)
+{
+	int ret = of_property_read_u32(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node,
+			const char *name, const char **value)
+{
+	int ret = of_property_read_string(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 width;
+	int ret = simplefb_read_u32_of(dev, of_node, "width", &width);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "width", width);
+}
+
+static int
+simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 height;
+	int ret = simplefb_read_u32_of(dev, of_node, "height", &height);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "height", height);
+}
+
+static int
+simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 stride;
+	int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int(dev, "stride", stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node)
+{
+	const char *format;
+	int ret = simplefb_read_string_of(dev, of_node, "format", &format);
+
+	if (ret)
+		return ERR_PTR(ret);
+	return simplefb_get_validated_format(dev, format);
+}
+
 /*
  * Simple Framebuffer device
  */
@@ -166,6 +234,7 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+	struct device_node *of_node = pdev->dev.of_node;
 
 	if (pd) {
 		width = simplefb_get_width_pd(dev, pd);
@@ -180,6 +249,19 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 		format = simplefb_get_format_pd(dev, pd);
 		if (IS_ERR(format))
 			return PTR_ERR(format);
+	} else if (of_node) {
+		width = simplefb_get_width_of(dev, of_node);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_of(dev, of_node);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_of(dev, of_node);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_of(dev, of_node);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
 	} else {
 		drm_err(dev, "no simplefb configuration found\n");
 		return -ENODEV;
@@ -516,9 +598,16 @@ static int simpledrm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id simpledrm_of_match_table[] = {
+	{ .compatible = "simple-framebuffer", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, simpledrm_of_match_table);
+
 static struct platform_driver simpledrm_platform_driver = {
 	.driver = {
 		.name = "simple-framebuffer", /* connect to sysfb */
+		.of_match_table = simpledrm_of_match_table,
 	},
 	.probe = simpledrm_probe,
 	.remove = simpledrm_remove,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 07/10] drm/simpledrm: Initialize framebuffer data from device-tree node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

A firmware framebuffer might also be specified via device-tree files. If
no device platform data is given, try the DT device node.

v2:
	* add Device Tree match table
	* clean-up parser wrappers

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 89 ++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 4f0d4ec0b432..c9cef2b50de6 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -114,6 +114,74 @@ simplefb_get_format_pd(struct drm_device *dev,
 	return simplefb_get_validated_format(dev, pd->format);
 }
 
+static int
+simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node,
+		     const char *name, u32 *value)
+{
+	int ret = of_property_read_u32(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node,
+			const char *name, const char **value)
+{
+	int ret = of_property_read_string(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 width;
+	int ret = simplefb_read_u32_of(dev, of_node, "width", &width);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "width", width);
+}
+
+static int
+simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 height;
+	int ret = simplefb_read_u32_of(dev, of_node, "height", &height);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "height", height);
+}
+
+static int
+simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 stride;
+	int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int(dev, "stride", stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node)
+{
+	const char *format;
+	int ret = simplefb_read_string_of(dev, of_node, "format", &format);
+
+	if (ret)
+		return ERR_PTR(ret);
+	return simplefb_get_validated_format(dev, format);
+}
+
 /*
  * Simple Framebuffer device
  */
@@ -166,6 +234,7 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+	struct device_node *of_node = pdev->dev.of_node;
 
 	if (pd) {
 		width = simplefb_get_width_pd(dev, pd);
@@ -180,6 +249,19 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 		format = simplefb_get_format_pd(dev, pd);
 		if (IS_ERR(format))
 			return PTR_ERR(format);
+	} else if (of_node) {
+		width = simplefb_get_width_of(dev, of_node);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_of(dev, of_node);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_of(dev, of_node);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_of(dev, of_node);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
 	} else {
 		drm_err(dev, "no simplefb configuration found\n");
 		return -ENODEV;
@@ -516,9 +598,16 @@ static int simpledrm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id simpledrm_of_match_table[] = {
+	{ .compatible = "simple-framebuffer", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, simpledrm_of_match_table);
+
 static struct platform_driver simpledrm_platform_driver = {
 	.driver = {
 		.name = "simple-framebuffer", /* connect to sysfb */
+		.of_match_table = simpledrm_of_match_table,
 	},
 	.probe = simpledrm_probe,
 	.remove = simpledrm_remove,
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 07/10] drm/simpledrm: Initialize framebuffer data from device-tree node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

A firmware framebuffer might also be specified via device-tree files. If
no device platform data is given, try the DT device node.

v2:
	* add Device Tree match table
	* clean-up parser wrappers

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 89 ++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 4f0d4ec0b432..c9cef2b50de6 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -114,6 +114,74 @@ simplefb_get_format_pd(struct drm_device *dev,
 	return simplefb_get_validated_format(dev, pd->format);
 }
 
+static int
+simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node,
+		     const char *name, u32 *value)
+{
+	int ret = of_property_read_u32(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node,
+			const char *name, const char **value)
+{
+	int ret = of_property_read_string(of_node, name, value);
+
+	if (ret)
+		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",
+			name, ret);
+	return ret;
+}
+
+static int
+simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 width;
+	int ret = simplefb_read_u32_of(dev, of_node, "width", &width);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "width", width);
+}
+
+static int
+simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 height;
+	int ret = simplefb_read_u32_of(dev, of_node, "height", &height);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int0(dev, "height", height);
+}
+
+static int
+simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node)
+{
+	u32 stride;
+	int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride);
+
+	if (ret)
+		return ret;
+	return simplefb_get_validated_int(dev, "stride", stride);
+}
+
+static const struct drm_format_info *
+simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node)
+{
+	const char *format;
+	int ret = simplefb_read_string_of(dev, of_node, "format", &format);
+
+	if (ret)
+		return ERR_PTR(ret);
+	return simplefb_get_validated_format(dev, format);
+}
+
 /*
  * Simple Framebuffer device
  */
@@ -166,6 +234,7 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
+	struct device_node *of_node = pdev->dev.of_node;
 
 	if (pd) {
 		width = simplefb_get_width_pd(dev, pd);
@@ -180,6 +249,19 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
 		format = simplefb_get_format_pd(dev, pd);
 		if (IS_ERR(format))
 			return PTR_ERR(format);
+	} else if (of_node) {
+		width = simplefb_get_width_of(dev, of_node);
+		if (width < 0)
+			return width;
+		height = simplefb_get_height_of(dev, of_node);
+		if (height < 0)
+			return height;
+		stride = simplefb_get_stride_of(dev, of_node);
+		if (stride < 0)
+			return stride;
+		format = simplefb_get_format_of(dev, of_node);
+		if (IS_ERR(format))
+			return PTR_ERR(format);
 	} else {
 		drm_err(dev, "no simplefb configuration found\n");
 		return -ENODEV;
@@ -516,9 +598,16 @@ static int simpledrm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id simpledrm_of_match_table[] = {
+	{ .compatible = "simple-framebuffer", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, simpledrm_of_match_table);
+
 static struct platform_driver simpledrm_platform_driver = {
 	.driver = {
 		.name = "simple-framebuffer", /* connect to sysfb */
+		.of_match_table = simpledrm_of_match_table,
 	},
 	.probe = simpledrm_probe,
 	.remove = simpledrm_remove,
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

Make sure required hardware clocks are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Clocks are released automatically via devres helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 108 +++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index c9cef2b50de6..10ca3373b61f 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/clk.h>
+#include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 
@@ -190,6 +192,12 @@ struct simpledrm_device {
 	struct drm_device dev;
 	struct platform_device *pdev;
 
+	/* clocks */
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+	unsigned int clk_count;
+	struct clk **clks;
+#endif
+
 	/* simplefb settings */
 	struct drm_display_mode mode;
 	const struct drm_format_info *format;
@@ -211,6 +219,103 @@ static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
 	return container_of(dev, struct simpledrm_device, dev);
 }
 
+/*
+ * Hardware
+ */
+
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+/*
+ * Clock handling code.
+ *
+ * Here we handle the clocks property of our "simple-framebuffer" dt node.
+ * This is necessary so that we can make sure that any clocks needed by
+ * the display engine that the bootloader set up for us (and for which it
+ * provided a simplefb dt node), stay up, for the life of the simplefb
+ * driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the clocks.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the clock definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_clocks(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct clk *clock;
+	unsigned int i;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	sdev->clk_count = of_clk_get_parent_count(of_node);
+	if (!sdev->clk_count)
+		return 0;
+
+	sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
+				  GFP_KERNEL);
+	if (!sdev->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		clock = of_clk_get(of_node, i);
+		if (IS_ERR(clock)) {
+			ret = PTR_ERR(clock);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "clock %u not found: %d\n", i, ret);
+			continue;
+		}
+		ret = clk_prepare_enable(clock);
+		if (ret) {
+			drm_err(dev, "failed to enable clock %u: %d\n",
+				i, ret);
+			clk_put(clock);
+		}
+		sdev->clks[i] = clock;
+	}
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_clocks,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -534,6 +639,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 		return ERR_CAST(sdev);
 	sdev->pdev = pdev;
 
+	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
 	if (ret)
 		return ERR_PTR(ret);
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Make sure required hardware clocks are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Clocks are released automatically via devres helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 108 +++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index c9cef2b50de6..10ca3373b61f 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/clk.h>
+#include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 
@@ -190,6 +192,12 @@ struct simpledrm_device {
 	struct drm_device dev;
 	struct platform_device *pdev;
 
+	/* clocks */
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+	unsigned int clk_count;
+	struct clk **clks;
+#endif
+
 	/* simplefb settings */
 	struct drm_display_mode mode;
 	const struct drm_format_info *format;
@@ -211,6 +219,103 @@ static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
 	return container_of(dev, struct simpledrm_device, dev);
 }
 
+/*
+ * Hardware
+ */
+
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+/*
+ * Clock handling code.
+ *
+ * Here we handle the clocks property of our "simple-framebuffer" dt node.
+ * This is necessary so that we can make sure that any clocks needed by
+ * the display engine that the bootloader set up for us (and for which it
+ * provided a simplefb dt node), stay up, for the life of the simplefb
+ * driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the clocks.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the clock definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_clocks(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct clk *clock;
+	unsigned int i;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	sdev->clk_count = of_clk_get_parent_count(of_node);
+	if (!sdev->clk_count)
+		return 0;
+
+	sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
+				  GFP_KERNEL);
+	if (!sdev->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		clock = of_clk_get(of_node, i);
+		if (IS_ERR(clock)) {
+			ret = PTR_ERR(clock);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "clock %u not found: %d\n", i, ret);
+			continue;
+		}
+		ret = clk_prepare_enable(clock);
+		if (ret) {
+			drm_err(dev, "failed to enable clock %u: %d\n",
+				i, ret);
+			clk_put(clock);
+		}
+		sdev->clks[i] = clock;
+	}
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_clocks,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -534,6 +639,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 		return ERR_CAST(sdev);
 	sdev->pdev = pdev;
 
+	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
 	if (ret)
 		return ERR_PTR(ret);
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Make sure required hardware clocks are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Clocks are released automatically via devres helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 108 +++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index c9cef2b50de6..10ca3373b61f 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/clk.h>
+#include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 
@@ -190,6 +192,12 @@ struct simpledrm_device {
 	struct drm_device dev;
 	struct platform_device *pdev;
 
+	/* clocks */
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+	unsigned int clk_count;
+	struct clk **clks;
+#endif
+
 	/* simplefb settings */
 	struct drm_display_mode mode;
 	const struct drm_format_info *format;
@@ -211,6 +219,103 @@ static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev)
 	return container_of(dev, struct simpledrm_device, dev);
 }
 
+/*
+ * Hardware
+ */
+
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+/*
+ * Clock handling code.
+ *
+ * Here we handle the clocks property of our "simple-framebuffer" dt node.
+ * This is necessary so that we can make sure that any clocks needed by
+ * the display engine that the bootloader set up for us (and for which it
+ * provided a simplefb dt node), stay up, for the life of the simplefb
+ * driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the clocks.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the clock definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_clocks(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct clk *clock;
+	unsigned int i;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	sdev->clk_count = of_clk_get_parent_count(of_node);
+	if (!sdev->clk_count)
+		return 0;
+
+	sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
+				  GFP_KERNEL);
+	if (!sdev->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < sdev->clk_count; ++i) {
+		clock = of_clk_get(of_node, i);
+		if (IS_ERR(clock)) {
+			ret = PTR_ERR(clock);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "clock %u not found: %d\n", i, ret);
+			continue;
+		}
+		ret = clk_prepare_enable(clock);
+		if (ret) {
+			drm_err(dev, "failed to enable clock %u: %d\n",
+				i, ret);
+			clk_put(clock);
+		}
+		sdev->clks[i] = clock;
+	}
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_clocks,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->clks[i]) {
+			clk_disable_unprepare(sdev->clks[i]);
+			clk_put(sdev->clks[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -534,6 +639,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 		return ERR_CAST(sdev);
 	sdev->pdev = pdev;
 
+	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
 	if (ret)
 		return ERR_PTR(ret);
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 09/10] drm/simpledrm: Acquire regulators from DT device node
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

Make sure required hardware regulators are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Regulators are released automatically via devres helpers.

v2:
	* use strscpy()

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 128 +++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 10ca3373b61f..2e27eeb791a1 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -4,6 +4,7 @@
 #include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
@@ -197,6 +198,11 @@ struct simpledrm_device {
 	unsigned int clk_count;
 	struct clk **clks;
 #endif
+	/* regulators */
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+	unsigned int regulator_count;
+	struct regulator **regulators;
+#endif
 
 	/* simplefb settings */
 	struct drm_display_mode mode;
@@ -316,6 +322,125 @@ static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
 }
 #endif
 
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+
+#define SUPPLY_SUFFIX "-supply"
+
+/*
+ * Regulator handling code.
+ *
+ * Here we handle the num-supplies and vin*-supply properties of our
+ * "simple-framebuffer" dt node. This is necessary so that we can make sure
+ * that any regulators needed by the display hardware that the bootloader
+ * set up for us (and for which it provided a simplefb dt node), stay up,
+ * for the life of the simplefb driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the
+ * regulators.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the regulator definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_regulators(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->regulator_count; ++i) {
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct property *prop;
+	struct regulator *regulator;
+	const char *p;
+	unsigned int count = 0, i = 0;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	/* Count the number of regulator supplies */
+	for_each_property_of_node(of_node, prop) {
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (p && p != prop->name)
+			++count;
+	}
+
+	if (!count)
+		return 0;
+
+	sdev->regulators = drmm_kzalloc(dev,
+					count * sizeof(sdev->regulators[0]),
+					GFP_KERNEL);
+	if (!sdev->regulators)
+		return -ENOMEM;
+
+	for_each_property_of_node(of_node, prop) {
+		char name[32]; /* 32 is max size of property name */
+		size_t len;
+
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (!p || p == prop->name)
+			continue;
+		len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1;
+		strscpy(name, prop->name, min(sizeof(name), len));
+
+		regulator = regulator_get_optional(&pdev->dev, name);
+		if (IS_ERR(regulator)) {
+			ret = PTR_ERR(regulator);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "regulator %s not found: %d\n",
+				name, ret);
+			continue;
+		}
+
+		ret = regulator_enable(regulator);
+		if (ret) {
+			drm_err(dev, "failed to enable regulator %u: %d\n",
+				i, ret);
+			regulator_put(regulator);
+		}
+
+		sdev->regulators[i++] = regulator;
+	}
+	sdev->regulator_count = i;
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_regulators,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -640,6 +765,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 	sdev->pdev = pdev;
 
 	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_regulators(sdev);
 	if (ret)
 		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 09/10] drm/simpledrm: Acquire regulators from DT device node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Make sure required hardware regulators are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Regulators are released automatically via devres helpers.

v2:
	* use strscpy()

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 128 +++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 10ca3373b61f..2e27eeb791a1 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -4,6 +4,7 @@
 #include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
@@ -197,6 +198,11 @@ struct simpledrm_device {
 	unsigned int clk_count;
 	struct clk **clks;
 #endif
+	/* regulators */
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+	unsigned int regulator_count;
+	struct regulator **regulators;
+#endif
 
 	/* simplefb settings */
 	struct drm_display_mode mode;
@@ -316,6 +322,125 @@ static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
 }
 #endif
 
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+
+#define SUPPLY_SUFFIX "-supply"
+
+/*
+ * Regulator handling code.
+ *
+ * Here we handle the num-supplies and vin*-supply properties of our
+ * "simple-framebuffer" dt node. This is necessary so that we can make sure
+ * that any regulators needed by the display hardware that the bootloader
+ * set up for us (and for which it provided a simplefb dt node), stay up,
+ * for the life of the simplefb driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the
+ * regulators.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the regulator definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_regulators(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->regulator_count; ++i) {
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct property *prop;
+	struct regulator *regulator;
+	const char *p;
+	unsigned int count = 0, i = 0;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	/* Count the number of regulator supplies */
+	for_each_property_of_node(of_node, prop) {
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (p && p != prop->name)
+			++count;
+	}
+
+	if (!count)
+		return 0;
+
+	sdev->regulators = drmm_kzalloc(dev,
+					count * sizeof(sdev->regulators[0]),
+					GFP_KERNEL);
+	if (!sdev->regulators)
+		return -ENOMEM;
+
+	for_each_property_of_node(of_node, prop) {
+		char name[32]; /* 32 is max size of property name */
+		size_t len;
+
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (!p || p == prop->name)
+			continue;
+		len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1;
+		strscpy(name, prop->name, min(sizeof(name), len));
+
+		regulator = regulator_get_optional(&pdev->dev, name);
+		if (IS_ERR(regulator)) {
+			ret = PTR_ERR(regulator);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "regulator %s not found: %d\n",
+				name, ret);
+			continue;
+		}
+
+		ret = regulator_enable(regulator);
+		if (ret) {
+			drm_err(dev, "failed to enable regulator %u: %d\n",
+				i, ret);
+			regulator_put(regulator);
+		}
+
+		sdev->regulators[i++] = regulator;
+	}
+	sdev->regulator_count = i;
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_regulators,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -640,6 +765,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 	sdev->pdev = pdev;
 
 	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_regulators(sdev);
 	if (ret)
 		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 09/10] drm/simpledrm: Acquire regulators from DT device node
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

Make sure required hardware regulators are enabled while the firmware
framebuffer is in use.

The basic code has been taken from the simplefb driver and adapted
to DRM. Regulators are released automatically via devres helpers.

v2:
	* use strscpy()

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/simpledrm.c | 128 +++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 10ca3373b61f..2e27eeb791a1 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -4,6 +4,7 @@
 #include <linux/of_clk.h>
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
@@ -197,6 +198,11 @@ struct simpledrm_device {
 	unsigned int clk_count;
 	struct clk **clks;
 #endif
+	/* regulators */
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+	unsigned int regulator_count;
+	struct regulator **regulators;
+#endif
 
 	/* simplefb settings */
 	struct drm_display_mode mode;
@@ -316,6 +322,125 @@ static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
 }
 #endif
 
+#if defined CONFIG_OF && defined CONFIG_REGULATOR
+
+#define SUPPLY_SUFFIX "-supply"
+
+/*
+ * Regulator handling code.
+ *
+ * Here we handle the num-supplies and vin*-supply properties of our
+ * "simple-framebuffer" dt node. This is necessary so that we can make sure
+ * that any regulators needed by the display hardware that the bootloader
+ * set up for us (and for which it provided a simplefb dt node), stay up,
+ * for the life of the simplefb driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the
+ * regulators.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the regulator definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+
+static void simpledrm_device_release_regulators(void *res)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(res);
+	unsigned int i;
+
+	for (i = 0; i < sdev->regulator_count; ++i) {
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+}
+
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	struct drm_device *dev = &sdev->dev;
+	struct platform_device *pdev = sdev->pdev;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct property *prop;
+	struct regulator *regulator;
+	const char *p;
+	unsigned int count = 0, i = 0;
+	int ret;
+
+	if (dev_get_platdata(&pdev->dev) || !of_node)
+		return 0;
+
+	/* Count the number of regulator supplies */
+	for_each_property_of_node(of_node, prop) {
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (p && p != prop->name)
+			++count;
+	}
+
+	if (!count)
+		return 0;
+
+	sdev->regulators = drmm_kzalloc(dev,
+					count * sizeof(sdev->regulators[0]),
+					GFP_KERNEL);
+	if (!sdev->regulators)
+		return -ENOMEM;
+
+	for_each_property_of_node(of_node, prop) {
+		char name[32]; /* 32 is max size of property name */
+		size_t len;
+
+		p = strstr(prop->name, SUPPLY_SUFFIX);
+		if (!p || p == prop->name)
+			continue;
+		len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1;
+		strscpy(name, prop->name, min(sizeof(name), len));
+
+		regulator = regulator_get_optional(&pdev->dev, name);
+		if (IS_ERR(regulator)) {
+			ret = PTR_ERR(regulator);
+			if (ret == -EPROBE_DEFER)
+				goto err;
+			drm_err(dev, "regulator %s not found: %d\n",
+				name, ret);
+			continue;
+		}
+
+		ret = regulator_enable(regulator);
+		if (ret) {
+			drm_err(dev, "failed to enable regulator %u: %d\n",
+				i, ret);
+			regulator_put(regulator);
+		}
+
+		sdev->regulators[i++] = regulator;
+	}
+	sdev->regulator_count = i;
+
+	return devm_add_action_or_reset(&pdev->dev,
+					simpledrm_device_release_regulators,
+					sdev);
+
+err:
+	while (i) {
+		--i;
+		if (sdev->regulators[i]) {
+			regulator_disable(sdev->regulators[i]);
+			regulator_put(sdev->regulators[i]);
+		}
+	}
+	return ret;
+}
+#else
+static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
+{
+	return 0;
+}
+#endif
+
 /*
  *  Simplefb settings
  */
@@ -640,6 +765,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev)
 	sdev->pdev = pdev;
 
 	ret = simpledrm_device_init_clocks(sdev);
+	if (ret)
+		return ERR_PTR(ret);
+	ret = simpledrm_device_init_regulators(sdev);
 	if (ret)
 		return ERR_PTR(ret);
 	ret = simpledrm_device_init_fb(sdev);
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 10/10] drm/simpledrm: Acquire memory aperture for framebuffer
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:29   ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization, Thomas Zimmermann

We register the simplekms device with the DRM platform helpers. A
native driver for the graphics hardware will kick-out the simpledrm
driver before taking over the device.

v2:
	* adapt to aperture changes
	* use drm_dev_unplug() and drm_dev_enter/exit()
	* don't split error string

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/Kconfig     |  1 +
 drivers/gpu/drm/tiny/simpledrm.c | 83 ++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index d46f95d9196d..5b72dd8e93f9 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -41,6 +41,7 @@ config DRM_GM12U320
 config DRM_SIMPLEDRM
 	tristate "Simple framebuffer driver"
 	depends on DRM
+	select DRM_APERTURE
 	select DRM_GEM_SHMEM_HELPER
 	select DRM_KMS_HELPER
 	help
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 2e27eeb791a1..67d33af19086 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -5,7 +5,9 @@
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
 
+#include <drm/drm_aperture.h>
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_damage_helper.h>
@@ -37,6 +39,12 @@
 #define SIMPLEDRM_MODE(hd, vd)	\
 	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
 
+/*
+ * Protects the platform device's drvdata against
+ * concurrent manipulation.
+ */
+static DEFINE_SPINLOCK(simpledrm_drvdata_lock);
+
 /*
  * Helpers for simplefb
  */
@@ -515,16 +523,53 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
  * Memory management
  */
 
+static void simpledrm_aperture_detach(struct drm_device *dev, resource_size_t base,
+				      resource_size_t size)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+	struct platform_device *pdev = sdev->pdev;
+
+	if (WARN_ON(drm_dev_is_unplugged(dev)))
+		return; /* BUG: driver already got detached */
+
+	/*
+	 * If simpledrm gets detached from the aperture, it's like unplugging
+	 * the device. So call drm_dev_unplug().
+	 */
+	drm_dev_unplug(dev);
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL); /* required; see simpledrm_remove() */
+	spin_unlock(&simpledrm_drvdata_lock);
+}
+
+static const struct drm_aperture_funcs simpledrm_aperture_funcs = {
+	.detach = simpledrm_aperture_detach,
+};
+
 static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
 {
+	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	struct resource *mem;
+	struct drm_aperture *ap;
 	void __iomem *screen_base;
+	int ret;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem)
 		return -EINVAL;
 
+	ap = devm_aperture_acquire(dev, mem->start, resource_size(mem),
+				   &simpledrm_aperture_funcs);
+	if (IS_ERR(ap)) {
+		ret = PTR_ERR(ap);
+		drm_err(dev, "could not acquire memory range [0x%llx:0x%llx]: error %d\n",
+			mem->start, mem->end, ret);
+		return ret;
+	}
+
 	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
 				      resource_size(mem));
 	if (!screen_base)
@@ -625,12 +670,18 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_device *dev = &sdev->dev;
+	int idx;
 
 	if (!fb)
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
 			    sdev->format->format, vmap, fb);
+	drm_dev_exit(idx);
 }
 
 static void
@@ -642,7 +693,9 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
 	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_device *dev = &sdev->dev;
 	struct drm_rect clip;
+	int idx;
 
 	if (!fb)
 		return;
@@ -650,8 +703,13 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
 				 sdev->format->format, vmap, fb, &clip);
+
+	drm_dev_exit(idx);
 }
 
 static const struct drm_simple_display_pipe_funcs
@@ -826,10 +884,29 @@ static int simpledrm_probe(struct platform_device *pdev)
 
 static int simpledrm_remove(struct platform_device *pdev)
 {
-	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
-	struct drm_device *dev = &sdev->dev;
+	struct simpledrm_device *sdev;
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+	spin_unlock(&simpledrm_drvdata_lock);
+
+	/*
+	 * The platform driver shares its reference to dev with the
+	 * platform helpers for apertures. That reference is either
+	 * released here when unloading the driver; or it's released
+	 * when the driver gets kicked out by another driver. In the
+	 * latter case, the aperture release routine clears the data
+	 * field of the platform device.
+	 *
+	 * Therefore, sdev being NULL is a valid state if the driver
+	 * has been kicked out by another DRM driver. In this case,
+	 * it's all been cleaned up and we can return immediately.
+	 */
+	if (!sdev)
+		return 0;
 
-	drm_dev_unregister(dev);
+	drm_dev_unplug(&sdev->dev);
 
 	return 0;
 }
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 10/10] drm/simpledrm: Acquire memory aperture for framebuffer
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

We register the simplekms device with the DRM platform helpers. A
native driver for the graphics hardware will kick-out the simpledrm
driver before taking over the device.

v2:
	* adapt to aperture changes
	* use drm_dev_unplug() and drm_dev_enter/exit()
	* don't split error string

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/Kconfig     |  1 +
 drivers/gpu/drm/tiny/simpledrm.c | 83 ++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index d46f95d9196d..5b72dd8e93f9 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -41,6 +41,7 @@ config DRM_GM12U320
 config DRM_SIMPLEDRM
 	tristate "Simple framebuffer driver"
 	depends on DRM
+	select DRM_APERTURE
 	select DRM_GEM_SHMEM_HELPER
 	select DRM_KMS_HELPER
 	help
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 2e27eeb791a1..67d33af19086 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -5,7 +5,9 @@
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
 
+#include <drm/drm_aperture.h>
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_damage_helper.h>
@@ -37,6 +39,12 @@
 #define SIMPLEDRM_MODE(hd, vd)	\
 	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
 
+/*
+ * Protects the platform device's drvdata against
+ * concurrent manipulation.
+ */
+static DEFINE_SPINLOCK(simpledrm_drvdata_lock);
+
 /*
  * Helpers for simplefb
  */
@@ -515,16 +523,53 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
  * Memory management
  */
 
+static void simpledrm_aperture_detach(struct drm_device *dev, resource_size_t base,
+				      resource_size_t size)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+	struct platform_device *pdev = sdev->pdev;
+
+	if (WARN_ON(drm_dev_is_unplugged(dev)))
+		return; /* BUG: driver already got detached */
+
+	/*
+	 * If simpledrm gets detached from the aperture, it's like unplugging
+	 * the device. So call drm_dev_unplug().
+	 */
+	drm_dev_unplug(dev);
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL); /* required; see simpledrm_remove() */
+	spin_unlock(&simpledrm_drvdata_lock);
+}
+
+static const struct drm_aperture_funcs simpledrm_aperture_funcs = {
+	.detach = simpledrm_aperture_detach,
+};
+
 static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
 {
+	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	struct resource *mem;
+	struct drm_aperture *ap;
 	void __iomem *screen_base;
+	int ret;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem)
 		return -EINVAL;
 
+	ap = devm_aperture_acquire(dev, mem->start, resource_size(mem),
+				   &simpledrm_aperture_funcs);
+	if (IS_ERR(ap)) {
+		ret = PTR_ERR(ap);
+		drm_err(dev, "could not acquire memory range [0x%llx:0x%llx]: error %d\n",
+			mem->start, mem->end, ret);
+		return ret;
+	}
+
 	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
 				      resource_size(mem));
 	if (!screen_base)
@@ -625,12 +670,18 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_device *dev = &sdev->dev;
+	int idx;
 
 	if (!fb)
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
 			    sdev->format->format, vmap, fb);
+	drm_dev_exit(idx);
 }
 
 static void
@@ -642,7 +693,9 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
 	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_device *dev = &sdev->dev;
 	struct drm_rect clip;
+	int idx;
 
 	if (!fb)
 		return;
@@ -650,8 +703,13 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
 				 sdev->format->format, vmap, fb, &clip);
+
+	drm_dev_exit(idx);
 }
 
 static const struct drm_simple_display_pipe_funcs
@@ -826,10 +884,29 @@ static int simpledrm_probe(struct platform_device *pdev)
 
 static int simpledrm_remove(struct platform_device *pdev)
 {
-	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
-	struct drm_device *dev = &sdev->dev;
+	struct simpledrm_device *sdev;
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+	spin_unlock(&simpledrm_drvdata_lock);
+
+	/*
+	 * The platform driver shares its reference to dev with the
+	 * platform helpers for apertures. That reference is either
+	 * released here when unloading the driver; or it's released
+	 * when the driver gets kicked out by another driver. In the
+	 * latter case, the aperture release routine clears the data
+	 * field of the platform device.
+	 *
+	 * Therefore, sdev being NULL is a valid state if the driver
+	 * has been kicked out by another DRM driver. In this case,
+	 * it's all been cleaned up and we can return immediately.
+	 */
+	if (!sdev)
+		return 0;
 
-	drm_dev_unregister(dev);
+	drm_dev_unplug(&sdev->dev);
 
 	return 0;
 }
-- 
2.30.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* [PATCH v2 10/10] drm/simpledrm: Acquire memory aperture for framebuffer
@ 2021-03-18 10:29   ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 10:29 UTC (permalink / raw)
  To: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger
  Cc: virtualization, Thomas Zimmermann, dri-devel, linux-doc

We register the simplekms device with the DRM platform helpers. A
native driver for the graphics hardware will kick-out the simpledrm
driver before taking over the device.

v2:
	* adapt to aperture changes
	* use drm_dev_unplug() and drm_dev_enter/exit()
	* don't split error string

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
---
 drivers/gpu/drm/tiny/Kconfig     |  1 +
 drivers/gpu/drm/tiny/simpledrm.c | 83 ++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index d46f95d9196d..5b72dd8e93f9 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -41,6 +41,7 @@ config DRM_GM12U320
 config DRM_SIMPLEDRM
 	tristate "Simple framebuffer driver"
 	depends on DRM
+	select DRM_APERTURE
 	select DRM_GEM_SHMEM_HELPER
 	select DRM_KMS_HELPER
 	help
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 2e27eeb791a1..67d33af19086 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -5,7 +5,9 @@
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
 
+#include <drm/drm_aperture.h>
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_damage_helper.h>
@@ -37,6 +39,12 @@
 #define SIMPLEDRM_MODE(hd, vd)	\
 	DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
 
+/*
+ * Protects the platform device's drvdata against
+ * concurrent manipulation.
+ */
+static DEFINE_SPINLOCK(simpledrm_drvdata_lock);
+
 /*
  * Helpers for simplefb
  */
@@ -515,16 +523,53 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev)
  * Memory management
  */
 
+static void simpledrm_aperture_detach(struct drm_device *dev, resource_size_t base,
+				      resource_size_t size)
+{
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+	struct platform_device *pdev = sdev->pdev;
+
+	if (WARN_ON(drm_dev_is_unplugged(dev)))
+		return; /* BUG: driver already got detached */
+
+	/*
+	 * If simpledrm gets detached from the aperture, it's like unplugging
+	 * the device. So call drm_dev_unplug().
+	 */
+	drm_dev_unplug(dev);
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL); /* required; see simpledrm_remove() */
+	spin_unlock(&simpledrm_drvdata_lock);
+}
+
+static const struct drm_aperture_funcs simpledrm_aperture_funcs = {
+	.detach = simpledrm_aperture_detach,
+};
+
 static int simpledrm_device_init_mm(struct simpledrm_device *sdev)
 {
+	struct drm_device *dev = &sdev->dev;
 	struct platform_device *pdev = sdev->pdev;
 	struct resource *mem;
+	struct drm_aperture *ap;
 	void __iomem *screen_base;
+	int ret;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem)
 		return -EINVAL;
 
+	ap = devm_aperture_acquire(dev, mem->start, resource_size(mem),
+				   &simpledrm_aperture_funcs);
+	if (IS_ERR(ap)) {
+		ret = PTR_ERR(ap);
+		drm_err(dev, "could not acquire memory range [0x%llx:0x%llx]: error %d\n",
+			mem->start, mem->end, ret);
+		return ret;
+	}
+
 	screen_base = devm_ioremap_wc(&pdev->dev, mem->start,
 				      resource_size(mem));
 	if (!screen_base)
@@ -625,12 +670,18 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	struct drm_framebuffer *fb = plane_state->fb;
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
+	struct drm_device *dev = &sdev->dev;
+	int idx;
 
 	if (!fb)
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch,
 			    sdev->format->format, vmap, fb);
+	drm_dev_exit(idx);
 }
 
 static void
@@ -642,7 +693,9 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 	void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */
 	struct drm_framebuffer *fb = plane_state->fb;
+	struct drm_device *dev = &sdev->dev;
 	struct drm_rect clip;
+	int idx;
 
 	if (!fb)
 		return;
@@ -650,8 +703,13 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip))
 		return;
 
+	if (!drm_dev_enter(dev, &idx))
+		return;
+
 	drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch,
 				 sdev->format->format, vmap, fb, &clip);
+
+	drm_dev_exit(idx);
 }
 
 static const struct drm_simple_display_pipe_funcs
@@ -826,10 +884,29 @@ static int simpledrm_probe(struct platform_device *pdev)
 
 static int simpledrm_remove(struct platform_device *pdev)
 {
-	struct simpledrm_device *sdev = platform_get_drvdata(pdev);
-	struct drm_device *dev = &sdev->dev;
+	struct simpledrm_device *sdev;
+
+	spin_lock(&simpledrm_drvdata_lock);
+	sdev = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+	spin_unlock(&simpledrm_drvdata_lock);
+
+	/*
+	 * The platform driver shares its reference to dev with the
+	 * platform helpers for apertures. That reference is either
+	 * released here when unloading the driver; or it's released
+	 * when the driver gets kicked out by another driver. In the
+	 * latter case, the aperture release routine clears the data
+	 * field of the platform device.
+	 *
+	 * Therefore, sdev being NULL is a valid state if the driver
+	 * has been kicked out by another DRM driver. In this case,
+	 * it's all been cleaned up and we can return immediately.
+	 */
+	if (!sdev)
+		return 0;
 
-	drm_dev_unregister(dev);
+	drm_dev_unplug(&sdev->dev);
 
 	return 0;
 }
-- 
2.30.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-03-18 10:29   ` Thomas Zimmermann
  (?)
@ 2021-03-18 10:39     ` Geert Uytterhoeven
  -1 siblings, 0 replies; 103+ messages in thread
From: Geert Uytterhoeven @ 2021-03-18 10:39 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Daniel Vetter, David Airlie, Maarten Lankhorst, Maxime Ripard,
	Gerd Hoffmann, Jonathan Corbet, Liam Girdwood, Mark Brown,
	Sam Ravnborg, Rob Herring, Emil Velikov, Hans de Goede,
	bluescreen_avenger, DRI Development, open list:DOCUMENTATION,
	virtualization

Hi Thomas,

On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Make sure required hardware clocks are enabled while the firmware
> framebuffer is in use.
>
> The basic code has been taken from the simplefb driver and adapted
> to DRM. Clocks are released automatically via devres helpers.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Thanks for your patch!

> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c

> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
> +{
> +       struct drm_device *dev = &sdev->dev;
> +       struct platform_device *pdev = sdev->pdev;
> +       struct device_node *of_node = pdev->dev.of_node;
> +       struct clk *clock;
> +       unsigned int i;
> +       int ret;
> +
> +       if (dev_get_platdata(&pdev->dev) || !of_node)
> +               return 0;
> +
> +       sdev->clk_count = of_clk_get_parent_count(of_node);
> +       if (!sdev->clk_count)
> +               return 0;
> +
> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
> +                                 GFP_KERNEL);
> +       if (!sdev->clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < sdev->clk_count; ++i) {
> +               clock = of_clk_get(of_node, i);
> +               if (IS_ERR(clock)) {
> +                       ret = PTR_ERR(clock);
> +                       if (ret == -EPROBE_DEFER)
> +                               goto err;
> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
> +                       continue;
> +               }
> +               ret = clk_prepare_enable(clock);
> +               if (ret) {
> +                       drm_err(dev, "failed to enable clock %u: %d\n",
> +                               i, ret);
> +                       clk_put(clock);
> +               }
> +               sdev->clks[i] = clock;
> +       }

of_clk_bulk_get_all() + clk_bulk_prepare_enable()?

There's also devm_clk_bulk_get_all(), but not for the OF variant.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 10:39     ` Geert Uytterhoeven
  0 siblings, 0 replies; 103+ messages in thread
From: Geert Uytterhoeven @ 2021-03-18 10:39 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Rob Herring, bluescreen_avenger, Jonathan Corbet, David Airlie,
	Emil Velikov, DRI Development, open list:DOCUMENTATION,
	Maarten Lankhorst, Liam Girdwood, Maxime Ripard, virtualization,
	Hans de Goede, Mark Brown, Daniel Vetter, Sam Ravnborg

Hi Thomas,

On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Make sure required hardware clocks are enabled while the firmware
> framebuffer is in use.
>
> The basic code has been taken from the simplefb driver and adapted
> to DRM. Clocks are released automatically via devres helpers.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Thanks for your patch!

> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c

> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
> +{
> +       struct drm_device *dev = &sdev->dev;
> +       struct platform_device *pdev = sdev->pdev;
> +       struct device_node *of_node = pdev->dev.of_node;
> +       struct clk *clock;
> +       unsigned int i;
> +       int ret;
> +
> +       if (dev_get_platdata(&pdev->dev) || !of_node)
> +               return 0;
> +
> +       sdev->clk_count = of_clk_get_parent_count(of_node);
> +       if (!sdev->clk_count)
> +               return 0;
> +
> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
> +                                 GFP_KERNEL);
> +       if (!sdev->clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < sdev->clk_count; ++i) {
> +               clock = of_clk_get(of_node, i);
> +               if (IS_ERR(clock)) {
> +                       ret = PTR_ERR(clock);
> +                       if (ret == -EPROBE_DEFER)
> +                               goto err;
> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
> +                       continue;
> +               }
> +               ret = clk_prepare_enable(clock);
> +               if (ret) {
> +                       drm_err(dev, "failed to enable clock %u: %d\n",
> +                               i, ret);
> +                       clk_put(clock);
> +               }
> +               sdev->clks[i] = clock;
> +       }

of_clk_bulk_get_all() + clk_bulk_prepare_enable()?

There's also devm_clk_bulk_get_all(), but not for the OF variant.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 10:39     ` Geert Uytterhoeven
  0 siblings, 0 replies; 103+ messages in thread
From: Geert Uytterhoeven @ 2021-03-18 10:39 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, Jonathan Corbet, David Airlie, Emil Velikov,
	DRI Development, open list:DOCUMENTATION, Liam Girdwood,
	virtualization, Hans de Goede, Mark Brown, Gerd Hoffmann,
	Sam Ravnborg

Hi Thomas,

On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Make sure required hardware clocks are enabled while the firmware
> framebuffer is in use.
>
> The basic code has been taken from the simplefb driver and adapted
> to DRM. Clocks are released automatically via devres helpers.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Thanks for your patch!

> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c

> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
> +{
> +       struct drm_device *dev = &sdev->dev;
> +       struct platform_device *pdev = sdev->pdev;
> +       struct device_node *of_node = pdev->dev.of_node;
> +       struct clk *clock;
> +       unsigned int i;
> +       int ret;
> +
> +       if (dev_get_platdata(&pdev->dev) || !of_node)
> +               return 0;
> +
> +       sdev->clk_count = of_clk_get_parent_count(of_node);
> +       if (!sdev->clk_count)
> +               return 0;
> +
> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
> +                                 GFP_KERNEL);
> +       if (!sdev->clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < sdev->clk_count; ++i) {
> +               clock = of_clk_get(of_node, i);
> +               if (IS_ERR(clock)) {
> +                       ret = PTR_ERR(clock);
> +                       if (ret == -EPROBE_DEFER)
> +                               goto err;
> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
> +                       continue;
> +               }
> +               ret = clk_prepare_enable(clock);
> +               if (ret) {
> +                       drm_err(dev, "failed to enable clock %u: %d\n",
> +                               i, ret);
> +                       clk_put(clock);
> +               }
> +               sdev->clks[i] = clock;
> +       }

of_clk_bulk_get_all() + clk_bulk_prepare_enable()?

There's also devm_clk_bulk_get_all(), but not for the OF variant.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-03-18 10:39     ` Geert Uytterhoeven
  (?)
@ 2021-03-18 11:00       ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 11:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: bluescreen_avenger, Jonathan Corbet, David Airlie, Emil Velikov,
	DRI Development, open list:DOCUMENTATION, Liam Girdwood,
	virtualization, Hans de Goede, Mark Brown, Gerd Hoffmann,
	Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 2837 bytes --]

Hi

Am 18.03.21 um 11:39 schrieb Geert Uytterhoeven:
> Hi Thomas,
> 
> On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Thanks for your patch!
> 
>> --- a/drivers/gpu/drm/tiny/simpledrm.c
>> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> 
>> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
>> +{
>> +       struct drm_device *dev = &sdev->dev;
>> +       struct platform_device *pdev = sdev->pdev;
>> +       struct device_node *of_node = pdev->dev.of_node;
>> +       struct clk *clock;
>> +       unsigned int i;
>> +       int ret;
>> +
>> +       if (dev_get_platdata(&pdev->dev) || !of_node)
>> +               return 0;
>> +
>> +       sdev->clk_count = of_clk_get_parent_count(of_node);
>> +       if (!sdev->clk_count)
>> +               return 0;
>> +
>> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
>> +                                 GFP_KERNEL);
>> +       if (!sdev->clks)
>> +               return -ENOMEM;
>> +
>> +       for (i = 0; i < sdev->clk_count; ++i) {
>> +               clock = of_clk_get(of_node, i);
>> +               if (IS_ERR(clock)) {
>> +                       ret = PTR_ERR(clock);
>> +                       if (ret == -EPROBE_DEFER)
>> +                               goto err;
>> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
>> +                       continue;
>> +               }
>> +               ret = clk_prepare_enable(clock);
>> +               if (ret) {
>> +                       drm_err(dev, "failed to enable clock %u: %d\n",
>> +                               i, ret);
>> +                       clk_put(clock);
>> +               }
>> +               sdev->clks[i] = clock;
>> +       }
> 
> of_clk_bulk_get_all() + clk_bulk_prepare_enable()?
> 
> There's also devm_clk_bulk_get_all(), but not for the OF variant.

Right, you mentioned this on the original patch set. I tried to use the 
functions, but TBH I found them to obfuscate the overall logic of the 
function. So I went back to the original code. Hopefully this is not too 
much of an issue.

Best regards
Thomas

> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 11:00       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 11:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: bluescreen_avenger, open list:DOCUMENTATION, David Airlie,
	Jonathan Corbet, Emil Velikov, Liam Girdwood, DRI Development,
	virtualization, Hans de Goede, Mark Brown, Sam Ravnborg


[-- Attachment #1.1.1: Type: text/plain, Size: 2837 bytes --]

Hi

Am 18.03.21 um 11:39 schrieb Geert Uytterhoeven:
> Hi Thomas,
> 
> On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Thanks for your patch!
> 
>> --- a/drivers/gpu/drm/tiny/simpledrm.c
>> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> 
>> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
>> +{
>> +       struct drm_device *dev = &sdev->dev;
>> +       struct platform_device *pdev = sdev->pdev;
>> +       struct device_node *of_node = pdev->dev.of_node;
>> +       struct clk *clock;
>> +       unsigned int i;
>> +       int ret;
>> +
>> +       if (dev_get_platdata(&pdev->dev) || !of_node)
>> +               return 0;
>> +
>> +       sdev->clk_count = of_clk_get_parent_count(of_node);
>> +       if (!sdev->clk_count)
>> +               return 0;
>> +
>> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
>> +                                 GFP_KERNEL);
>> +       if (!sdev->clks)
>> +               return -ENOMEM;
>> +
>> +       for (i = 0; i < sdev->clk_count; ++i) {
>> +               clock = of_clk_get(of_node, i);
>> +               if (IS_ERR(clock)) {
>> +                       ret = PTR_ERR(clock);
>> +                       if (ret == -EPROBE_DEFER)
>> +                               goto err;
>> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
>> +                       continue;
>> +               }
>> +               ret = clk_prepare_enable(clock);
>> +               if (ret) {
>> +                       drm_err(dev, "failed to enable clock %u: %d\n",
>> +                               i, ret);
>> +                       clk_put(clock);
>> +               }
>> +               sdev->clks[i] = clock;
>> +       }
> 
> of_clk_bulk_get_all() + clk_bulk_prepare_enable()?
> 
> There's also devm_clk_bulk_get_all(), but not for the OF variant.

Right, you mentioned this on the original patch set. I tried to use the 
functions, but TBH I found them to obfuscate the overall logic of the 
function. So I went back to the original code. Hopefully this is not too 
much of an issue.

Best regards
Thomas

> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-03-18 11:00       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-18 11:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: bluescreen_avenger, open list:DOCUMENTATION, David Airlie,
	Jonathan Corbet, Emil Velikov, Liam Girdwood, DRI Development,
	virtualization, Hans de Goede, Mark Brown, Gerd Hoffmann,
	Sam Ravnborg


[-- Attachment #1.1.1: Type: text/plain, Size: 2837 bytes --]

Hi

Am 18.03.21 um 11:39 schrieb Geert Uytterhoeven:
> Hi Thomas,
> 
> On Thu, Mar 18, 2021 at 11:29 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Thanks for your patch!
> 
>> --- a/drivers/gpu/drm/tiny/simpledrm.c
>> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> 
>> +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev)
>> +{
>> +       struct drm_device *dev = &sdev->dev;
>> +       struct platform_device *pdev = sdev->pdev;
>> +       struct device_node *of_node = pdev->dev.of_node;
>> +       struct clk *clock;
>> +       unsigned int i;
>> +       int ret;
>> +
>> +       if (dev_get_platdata(&pdev->dev) || !of_node)
>> +               return 0;
>> +
>> +       sdev->clk_count = of_clk_get_parent_count(of_node);
>> +       if (!sdev->clk_count)
>> +               return 0;
>> +
>> +       sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),
>> +                                 GFP_KERNEL);
>> +       if (!sdev->clks)
>> +               return -ENOMEM;
>> +
>> +       for (i = 0; i < sdev->clk_count; ++i) {
>> +               clock = of_clk_get(of_node, i);
>> +               if (IS_ERR(clock)) {
>> +                       ret = PTR_ERR(clock);
>> +                       if (ret == -EPROBE_DEFER)
>> +                               goto err;
>> +                       drm_err(dev, "clock %u not found: %d\n", i, ret);
>> +                       continue;
>> +               }
>> +               ret = clk_prepare_enable(clock);
>> +               if (ret) {
>> +                       drm_err(dev, "failed to enable clock %u: %d\n",
>> +                               i, ret);
>> +                       clk_put(clock);
>> +               }
>> +               sdev->clks[i] = clock;
>> +       }
> 
> of_clk_bulk_get_all() + clk_bulk_prepare_enable()?
> 
> There's also devm_clk_bulk_get_all(), but not for the OF variant.

Right, you mentioned this on the original patch set. I tried to use the 
functions, but TBH I found them to obfuscate the overall logic of the 
function. So I went back to the original code. Hopefully this is not too 
much of an issue.

Best regards
Thomas

> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-18 10:29 ` Thomas Zimmermann
  (?)
@ 2021-03-25 11:29   ` Hans de Goede
  -1 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-25 11:29 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization

Hi,

On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> This patchset adds support for simple-framebuffer platform devices and
> a handover mechanism for native drivers to take-over control of the
> hardware.
> 
> The new driver, called simpledrm, binds to a simple-frambuffer platform
> device. The kernel's boot code creates such devices for firmware-provided
> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> loader sets up the framebuffers. Description via device tree is also an
> option.
> 
> Simpledrm is small enough to be linked into the kernel. The driver's main
> purpose is to provide graphical output during the early phases of the boot
> process, before the native DRM drivers are available. Native drivers are
> typically loaded from an initrd ram disk. Occationally simpledrm can also
> serve as interim solution on graphics hardware without native DRM driver.
> 
> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> simplefb, for early-boot graphical output. However fbdev is deprecated and
> the drivers do not provide DRM interfaces for modern userspace.
> 
> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> 
> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> framebuffer's I/O-memory range and provides a callback function to be
> removed by a native driver. The native driver will remove simpledrm before
> taking over the hardware. The removal is integrated into existing helpers,
> so drivers use it automatically.
> 
> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> regulators. It's based on the simplefb drivers, but has been modified for
> DRM.

Thank you for your work on this, this is very interesting.

> I've also been working on fastboot support (i.e., flicker-free booting).
> This requires state-readout from simpledrm via generic interfaces, as
> outlined in [1]. I do have some prototype code, but it will take a while
> to get this ready. Simpledrm will then support it.
> 
> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> reliably. The fbdev console and Weston work automatically. Xorg requires
> manual configuration of the device. Xorgs current modesetting driver does
> not work with both, platform and PCI device, for the same physical
> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> I expect the problem to become a non-issue soon. Additional testing has
> been reported at [2].
> 
> One cosmetical issue is that simpledrm's device file is card0 and the
> native driver's device file is card1. After simpledrm has been kicked out,
> only card1 is left. This does not seem to be a practical problem however.
> 
> TODO/IDEAS:
> 
> 	* provide deferred takeover

I'm not sure what you mean with this ?  Currently deferred-takeover is
handled in the fbcon code. Current flickerfree boot works like this
(assuming a single LCD panel in a laptop):

1. EFI/GOP sets up the framebuffer, draws a vendor logo
2. The bootloader runs in silent mode and does not touch anything gfx related
3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
   to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
   the console and leaves the dummy-console driver in place (unless there have already
   been kernel messages logged, which there shouldn't because loglevel=3)
3. i915 loads, reads out the hw state compares this to the preferred-mode for the
   panel which it would set, they match, nothing happens. i915 takes ownership
   of the scanout-buffer set up by the GOP, but leaves it in place.
   i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
   device, fbcon is notified of this, but is still deferred and leaves the dummy
   console driver in place as console driver.
4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
   plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
   scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
   scanout-buffer on the crtc, this is done atomically during vsync, so the user
   sees no changes, other then the spinner appearing
   (note the active VT is now in graphical mode)
5. From here on not flickering is a userspace problem

AFAICT this should work fine with simplekms too, unless it clears the screen
to black when it binds.

An addition to the above sequence, if at any time either the kernel or userspace
prints a message to the console; and at that time a fbdev is registered then fbcon
will takeover as the console driver from the dummy driver and it will start drawing
to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
where printend while no fbdev was registered, then fbcon will takeover the console
as soon as a fbdev gets registered.

So since we already have deferred-takeover in the fbcon code, I wonder what you
mean when you are talking about "provide deferred takeover" for simplekms?

Regards,

Hans


1) Except when the VT has been switched to GFX mode when this happens, then fbcon
will delay using the fbdev until the VT is switched back to text mode.


p.s.

This has the interesting side effect then when logging into a desktop GUI session:
kernel -> plymouth -> gdm -> GNOME user session

There never is any output to the text-console and fbcon never takes-over, so on
many Laptops running say Fedora workstation the fbcon code is actually unused
until the user manually switches to another virtual-console to log in in
text-mode:

[hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
[    0.258904] Console: colour dummy device 80x25
[    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
[    1.274768] fbcon: Deferring console take-over
[    2.540894] fbcon: i915drmfb (fb0) is primary device
[    2.540896] fbcon: Deferring console take-over
[hans@x1 ~]$ uptime
 12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81

Look mom no fbcon




> 	* provide bootsplash DRM client
> 	* make simplekms usable with ARM-EFI fbs
> 
> v2:
> 	* rename to simpledrm, aperture helpers
> 	* reorganized patches
> 	* use hotplug helpers for removal (Daniel)
> 	* added DT match tables (Rob)
> 	* use shadow-plane helpers
> 	* lots of minor cleanups
> 
> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> 
> Thomas Zimmermann (10):
>   drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>   drm/format-helper: Add blitter functions
>   drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>   drm/aperture: Add infrastructure for aperture ownership
>   drm: Add simpledrm driver
>   drm/simpledrm: Add fbdev emulation
>   drm/simpledrm: Initialize framebuffer data from device-tree node
>   drm/simpledrm: Acquire clocks from DT device node
>   drm/simpledrm: Acquire regulators from DT device node
>   drm/simpledrm: Acquire memory aperture for framebuffer
> 
>  Documentation/gpu/drm-internals.rst    |  12 +
>  MAINTAINERS                            |   7 +
>  drivers/gpu/drm/Kconfig                |   7 +
>  drivers/gpu/drm/Makefile               |   1 +
>  drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>  drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>  drivers/gpu/drm/tiny/Kconfig           |  17 +
>  drivers/gpu/drm/tiny/Makefile          |   1 +
>  drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>  drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>  include/drm/drm_aperture.h             |  96 +++
>  include/drm/drm_fb_helper.h            |  56 +-
>  include/drm/drm_format_helper.h        |  10 +-
>  14 files changed, 1466 insertions(+), 60 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
>  create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>  create mode 100644 include/drm/drm_aperture.h
> 
> --
> 2.30.1
> 


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-25 11:29   ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-25 11:29 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc

Hi,

On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> This patchset adds support for simple-framebuffer platform devices and
> a handover mechanism for native drivers to take-over control of the
> hardware.
> 
> The new driver, called simpledrm, binds to a simple-frambuffer platform
> device. The kernel's boot code creates such devices for firmware-provided
> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> loader sets up the framebuffers. Description via device tree is also an
> option.
> 
> Simpledrm is small enough to be linked into the kernel. The driver's main
> purpose is to provide graphical output during the early phases of the boot
> process, before the native DRM drivers are available. Native drivers are
> typically loaded from an initrd ram disk. Occationally simpledrm can also
> serve as interim solution on graphics hardware without native DRM driver.
> 
> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> simplefb, for early-boot graphical output. However fbdev is deprecated and
> the drivers do not provide DRM interfaces for modern userspace.
> 
> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> 
> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> framebuffer's I/O-memory range and provides a callback function to be
> removed by a native driver. The native driver will remove simpledrm before
> taking over the hardware. The removal is integrated into existing helpers,
> so drivers use it automatically.
> 
> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> regulators. It's based on the simplefb drivers, but has been modified for
> DRM.

Thank you for your work on this, this is very interesting.

> I've also been working on fastboot support (i.e., flicker-free booting).
> This requires state-readout from simpledrm via generic interfaces, as
> outlined in [1]. I do have some prototype code, but it will take a while
> to get this ready. Simpledrm will then support it.
> 
> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> reliably. The fbdev console and Weston work automatically. Xorg requires
> manual configuration of the device. Xorgs current modesetting driver does
> not work with both, platform and PCI device, for the same physical
> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> I expect the problem to become a non-issue soon. Additional testing has
> been reported at [2].
> 
> One cosmetical issue is that simpledrm's device file is card0 and the
> native driver's device file is card1. After simpledrm has been kicked out,
> only card1 is left. This does not seem to be a practical problem however.
> 
> TODO/IDEAS:
> 
> 	* provide deferred takeover

I'm not sure what you mean with this ?  Currently deferred-takeover is
handled in the fbcon code. Current flickerfree boot works like this
(assuming a single LCD panel in a laptop):

1. EFI/GOP sets up the framebuffer, draws a vendor logo
2. The bootloader runs in silent mode and does not touch anything gfx related
3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
   to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
   the console and leaves the dummy-console driver in place (unless there have already
   been kernel messages logged, which there shouldn't because loglevel=3)
3. i915 loads, reads out the hw state compares this to the preferred-mode for the
   panel which it would set, they match, nothing happens. i915 takes ownership
   of the scanout-buffer set up by the GOP, but leaves it in place.
   i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
   device, fbcon is notified of this, but is still deferred and leaves the dummy
   console driver in place as console driver.
4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
   plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
   scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
   scanout-buffer on the crtc, this is done atomically during vsync, so the user
   sees no changes, other then the spinner appearing
   (note the active VT is now in graphical mode)
5. From here on not flickering is a userspace problem

AFAICT this should work fine with simplekms too, unless it clears the screen
to black when it binds.

An addition to the above sequence, if at any time either the kernel or userspace
prints a message to the console; and at that time a fbdev is registered then fbcon
will takeover as the console driver from the dummy driver and it will start drawing
to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
where printend while no fbdev was registered, then fbcon will takeover the console
as soon as a fbdev gets registered.

So since we already have deferred-takeover in the fbcon code, I wonder what you
mean when you are talking about "provide deferred takeover" for simplekms?

Regards,

Hans


1) Except when the VT has been switched to GFX mode when this happens, then fbcon
will delay using the fbdev until the VT is switched back to text mode.


p.s.

This has the interesting side effect then when logging into a desktop GUI session:
kernel -> plymouth -> gdm -> GNOME user session

There never is any output to the text-console and fbcon never takes-over, so on
many Laptops running say Fedora workstation the fbcon code is actually unused
until the user manually switches to another virtual-console to log in in
text-mode:

[hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
[    0.258904] Console: colour dummy device 80x25
[    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
[    1.274768] fbcon: Deferring console take-over
[    2.540894] fbcon: i915drmfb (fb0) is primary device
[    2.540896] fbcon: Deferring console take-over
[hans@x1 ~]$ uptime
 12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81

Look mom no fbcon




> 	* provide bootsplash DRM client
> 	* make simplekms usable with ARM-EFI fbs
> 
> v2:
> 	* rename to simpledrm, aperture helpers
> 	* reorganized patches
> 	* use hotplug helpers for removal (Daniel)
> 	* added DT match tables (Rob)
> 	* use shadow-plane helpers
> 	* lots of minor cleanups
> 
> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> 
> Thomas Zimmermann (10):
>   drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>   drm/format-helper: Add blitter functions
>   drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>   drm/aperture: Add infrastructure for aperture ownership
>   drm: Add simpledrm driver
>   drm/simpledrm: Add fbdev emulation
>   drm/simpledrm: Initialize framebuffer data from device-tree node
>   drm/simpledrm: Acquire clocks from DT device node
>   drm/simpledrm: Acquire regulators from DT device node
>   drm/simpledrm: Acquire memory aperture for framebuffer
> 
>  Documentation/gpu/drm-internals.rst    |  12 +
>  MAINTAINERS                            |   7 +
>  drivers/gpu/drm/Kconfig                |   7 +
>  drivers/gpu/drm/Makefile               |   1 +
>  drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>  drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>  drivers/gpu/drm/tiny/Kconfig           |  17 +
>  drivers/gpu/drm/tiny/Makefile          |   1 +
>  drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>  drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>  include/drm/drm_aperture.h             |  96 +++
>  include/drm/drm_fb_helper.h            |  56 +-
>  include/drm/drm_format_helper.h        |  10 +-
>  14 files changed, 1466 insertions(+), 60 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
>  create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>  create mode 100644 include/drm/drm_aperture.h
> 
> --
> 2.30.1
> 

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-25 11:29   ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-25 11:29 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc

Hi,

On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> This patchset adds support for simple-framebuffer platform devices and
> a handover mechanism for native drivers to take-over control of the
> hardware.
> 
> The new driver, called simpledrm, binds to a simple-frambuffer platform
> device. The kernel's boot code creates such devices for firmware-provided
> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> loader sets up the framebuffers. Description via device tree is also an
> option.
> 
> Simpledrm is small enough to be linked into the kernel. The driver's main
> purpose is to provide graphical output during the early phases of the boot
> process, before the native DRM drivers are available. Native drivers are
> typically loaded from an initrd ram disk. Occationally simpledrm can also
> serve as interim solution on graphics hardware without native DRM driver.
> 
> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> simplefb, for early-boot graphical output. However fbdev is deprecated and
> the drivers do not provide DRM interfaces for modern userspace.
> 
> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> 
> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> framebuffer's I/O-memory range and provides a callback function to be
> removed by a native driver. The native driver will remove simpledrm before
> taking over the hardware. The removal is integrated into existing helpers,
> so drivers use it automatically.
> 
> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> regulators. It's based on the simplefb drivers, but has been modified for
> DRM.

Thank you for your work on this, this is very interesting.

> I've also been working on fastboot support (i.e., flicker-free booting).
> This requires state-readout from simpledrm via generic interfaces, as
> outlined in [1]. I do have some prototype code, but it will take a while
> to get this ready. Simpledrm will then support it.
> 
> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> reliably. The fbdev console and Weston work automatically. Xorg requires
> manual configuration of the device. Xorgs current modesetting driver does
> not work with both, platform and PCI device, for the same physical
> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> I expect the problem to become a non-issue soon. Additional testing has
> been reported at [2].
> 
> One cosmetical issue is that simpledrm's device file is card0 and the
> native driver's device file is card1. After simpledrm has been kicked out,
> only card1 is left. This does not seem to be a practical problem however.
> 
> TODO/IDEAS:
> 
> 	* provide deferred takeover

I'm not sure what you mean with this ?  Currently deferred-takeover is
handled in the fbcon code. Current flickerfree boot works like this
(assuming a single LCD panel in a laptop):

1. EFI/GOP sets up the framebuffer, draws a vendor logo
2. The bootloader runs in silent mode and does not touch anything gfx related
3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
   to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
   the console and leaves the dummy-console driver in place (unless there have already
   been kernel messages logged, which there shouldn't because loglevel=3)
3. i915 loads, reads out the hw state compares this to the preferred-mode for the
   panel which it would set, they match, nothing happens. i915 takes ownership
   of the scanout-buffer set up by the GOP, but leaves it in place.
   i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
   device, fbcon is notified of this, but is still deferred and leaves the dummy
   console driver in place as console driver.
4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
   plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
   scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
   scanout-buffer on the crtc, this is done atomically during vsync, so the user
   sees no changes, other then the spinner appearing
   (note the active VT is now in graphical mode)
5. From here on not flickering is a userspace problem

AFAICT this should work fine with simplekms too, unless it clears the screen
to black when it binds.

An addition to the above sequence, if at any time either the kernel or userspace
prints a message to the console; and at that time a fbdev is registered then fbcon
will takeover as the console driver from the dummy driver and it will start drawing
to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
where printend while no fbdev was registered, then fbcon will takeover the console
as soon as a fbdev gets registered.

So since we already have deferred-takeover in the fbcon code, I wonder what you
mean when you are talking about "provide deferred takeover" for simplekms?

Regards,

Hans


1) Except when the VT has been switched to GFX mode when this happens, then fbcon
will delay using the fbdev until the VT is switched back to text mode.


p.s.

This has the interesting side effect then when logging into a desktop GUI session:
kernel -> plymouth -> gdm -> GNOME user session

There never is any output to the text-console and fbcon never takes-over, so on
many Laptops running say Fedora workstation the fbcon code is actually unused
until the user manually switches to another virtual-console to log in in
text-mode:

[hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
[    0.258904] Console: colour dummy device 80x25
[    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
[    1.274768] fbcon: Deferring console take-over
[    2.540894] fbcon: i915drmfb (fb0) is primary device
[    2.540896] fbcon: Deferring console take-over
[hans@x1 ~]$ uptime
 12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81

Look mom no fbcon




> 	* provide bootsplash DRM client
> 	* make simplekms usable with ARM-EFI fbs
> 
> v2:
> 	* rename to simpledrm, aperture helpers
> 	* reorganized patches
> 	* use hotplug helpers for removal (Daniel)
> 	* added DT match tables (Rob)
> 	* use shadow-plane helpers
> 	* lots of minor cleanups
> 
> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> 
> Thomas Zimmermann (10):
>   drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>   drm/format-helper: Add blitter functions
>   drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>   drm/aperture: Add infrastructure for aperture ownership
>   drm: Add simpledrm driver
>   drm/simpledrm: Add fbdev emulation
>   drm/simpledrm: Initialize framebuffer data from device-tree node
>   drm/simpledrm: Acquire clocks from DT device node
>   drm/simpledrm: Acquire regulators from DT device node
>   drm/simpledrm: Acquire memory aperture for framebuffer
> 
>  Documentation/gpu/drm-internals.rst    |  12 +
>  MAINTAINERS                            |   7 +
>  drivers/gpu/drm/Kconfig                |   7 +
>  drivers/gpu/drm/Makefile               |   1 +
>  drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>  drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>  drivers/gpu/drm/tiny/Kconfig           |  17 +
>  drivers/gpu/drm/tiny/Makefile          |   1 +
>  drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>  drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>  include/drm/drm_aperture.h             |  96 +++
>  include/drm/drm_fb_helper.h            |  56 +-
>  include/drm/drm_format_helper.h        |  10 +-
>  14 files changed, 1466 insertions(+), 60 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
>  create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>  create mode 100644 include/drm/drm_aperture.h
> 
> --
> 2.30.1
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-18 10:29 ` Thomas Zimmermann
                   ` (12 preceding siblings ...)
  (?)
@ 2021-03-26  2:31 ` nerdopolis
  -1 siblings, 0 replies; 103+ messages in thread
From: nerdopolis @ 2021-03-26  2:31 UTC (permalink / raw)
  To: dri-devel

On Thursday, March 18, 2021 6:29:11 AM EDT Thomas Zimmermann wrote:
> This patchset adds support for simple-framebuffer platform devices and
> a handover mechanism for native drivers to take-over control of the
> hardware.
> 
> The new driver, called simpledrm, binds to a simple-frambuffer platform
> device. The kernel's boot code creates such devices for firmware-provided
> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> loader sets up the framebuffers. Description via device tree is also an
> option.
> 
> Simpledrm is small enough to be linked into the kernel. The driver's main
> purpose is to provide graphical output during the early phases of the boot
> process, before the native DRM drivers are available. Native drivers are
> typically loaded from an initrd ram disk. Occationally simpledrm can also
> serve as interim solution on graphics hardware without native DRM driver.
> 
> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> simplefb, for early-boot graphical output. However fbdev is deprecated and
> the drivers do not provide DRM interfaces for modern userspace.
> 
> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> 
> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> framebuffer's I/O-memory range and provides a callback function to be
> removed by a native driver. The native driver will remove simpledrm before
> taking over the hardware. The removal is integrated into existing helpers,
> so drivers use it automatically.
> 
> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> regulators. It's based on the simplefb drivers, but has been modified for
> DRM.
> 
> I've also been working on fastboot support (i.e., flicker-free booting).
> This requires state-readout from simpledrm via generic interfaces, as
> outlined in [1]. I do have some prototype code, but it will take a while
> to get this ready. Simpledrm will then support it.
> 
> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> reliably. The fbdev console and Weston work automatically. Xorg requires
> manual configuration of the device. Xorgs current modesetting driver does
> not work with both, platform and PCI device, for the same physical
> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> I expect the problem to become a non-issue soon. Additional testing has
> been reported at [2].
> 
> One cosmetical issue is that simpledrm's device file is card0 and the
> native driver's device file is card1. After simpledrm has been kicked out,
> only card1 is left. This does not seem to be a practical problem however.
> 
> TODO/IDEAS:
> 
> 	* provide deferred takeover
> 	* provide bootsplash DRM client
> 	* make simplekms usable with ARM-EFI fbs
> 
> v2:
> 	* rename to simpledrm, aperture helpers
> 	* reorganized patches
> 	* use hotplug helpers for removal (Daniel)
> 	* added DT match tables (Rob)
> 	* use shadow-plane helpers
> 	* lots of minor cleanups
> 
> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> 
> Thomas Zimmermann (10):
>   drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>   drm/format-helper: Add blitter functions
>   drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>   drm/aperture: Add infrastructure for aperture ownership
>   drm: Add simpledrm driver
>   drm/simpledrm: Add fbdev emulation
>   drm/simpledrm: Initialize framebuffer data from device-tree node
>   drm/simpledrm: Acquire clocks from DT device node
>   drm/simpledrm: Acquire regulators from DT device node
>   drm/simpledrm: Acquire memory aperture for framebuffer
> 
>  Documentation/gpu/drm-internals.rst    |  12 +
>  MAINTAINERS                            |   7 +
>  drivers/gpu/drm/Kconfig                |   7 +
>  drivers/gpu/drm/Makefile               |   1 +
>  drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>  drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>  drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>  drivers/gpu/drm/tiny/Kconfig           |  17 +
>  drivers/gpu/drm/tiny/Makefile          |   1 +
>  drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>  drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>  include/drm/drm_aperture.h             |  96 +++
>  include/drm/drm_fb_helper.h            |  56 +-
>  include/drm/drm_format_helper.h        |  10 +-
>  14 files changed, 1466 insertions(+), 60 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
>  create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>  create mode 100644 include/drm/drm_aperture.h
> 
> --
> 2.30.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
Hi

Testing the new version against drm-next and it works! I found I had to turn
off building CONFIG_FB_SIMPLE as it was taking over as the VGA device before 
simpledrm (or something. But it works, and as with the older version, testing
with the 'vmware' device that QEMU supports as a graphics device now has mode 
setting support which is pretty cool

Thanks

Thanks



_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-25 11:29   ` Hans de Goede
  (?)
@ 2021-03-29 12:31     ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-29 12:31 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 9780 bytes --]

Hi

Am 25.03.21 um 12:29 schrieb Hans de Goede:
> Hi,
> 
> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>> This patchset adds support for simple-framebuffer platform devices and
>> a handover mechanism for native drivers to take-over control of the
>> hardware.
>>
>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>> device. The kernel's boot code creates such devices for firmware-provided
>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>> loader sets up the framebuffers. Description via device tree is also an
>> option.
>>
>> Simpledrm is small enough to be linked into the kernel. The driver's main
>> purpose is to provide graphical output during the early phases of the boot
>> process, before the native DRM drivers are available. Native drivers are
>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>> serve as interim solution on graphics hardware without native DRM driver.
>>
>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>> the drivers do not provide DRM interfaces for modern userspace.
>>
>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>
>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>> framebuffer's I/O-memory range and provides a callback function to be
>> removed by a native driver. The native driver will remove simpledrm before
>> taking over the hardware. The removal is integrated into existing helpers,
>> so drivers use it automatically.
>>
>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>> regulators. It's based on the simplefb drivers, but has been modified for
>> DRM.
> 
> Thank you for your work on this, this is very interesting.
> 
>> I've also been working on fastboot support (i.e., flicker-free booting).
>> This requires state-readout from simpledrm via generic interfaces, as
>> outlined in [1]. I do have some prototype code, but it will take a while
>> to get this ready. Simpledrm will then support it.
>>
>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>> reliably. The fbdev console and Weston work automatically. Xorg requires
>> manual configuration of the device. Xorgs current modesetting driver does
>> not work with both, platform and PCI device, for the same physical
>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>> I expect the problem to become a non-issue soon. Additional testing has
>> been reported at [2].
>>
>> One cosmetical issue is that simpledrm's device file is card0 and the
>> native driver's device file is card1. After simpledrm has been kicked out,
>> only card1 is left. This does not seem to be a practical problem however.
>>
>> TODO/IDEAS:
>>
>> 	* provide deferred takeover
> 
> I'm not sure what you mean with this ?  Currently deferred-takeover is
> handled in the fbcon code. Current flickerfree boot works like this
> (assuming a single LCD panel in a laptop):
> 
> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> 2. The bootloader runs in silent mode and does not touch anything gfx related
> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>     the console and leaves the dummy-console driver in place (unless there have already
>     been kernel messages logged, which there shouldn't because loglevel=3)
> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>     panel which it would set, they match, nothing happens. i915 takes ownership
>     of the scanout-buffer set up by the GOP, but leaves it in place.
>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>     console driver in place as console driver.
> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>     sees no changes, other then the spinner appearing
>     (note the active VT is now in graphical mode)
> 5. From here on not flickering is a userspace problem
> 
> AFAICT this should work fine with simplekms too, unless it clears the screen
> to black when it binds.

I forgot to add the code that clears the screen, but that's the case here.

Instead of a plane-disable operation, simpledrm can at best clear the 
screen. This would happen during the initial mode-config reset IIRC. But 
we need to keep the display content stored in a framebuffer, so read-out 
helpers are required. There are more users of these read-out helpers. 
Adding them at some point probably makes sense.

Other drivers might also want to read the initial config from simpledrm 
via read-out helpers. I think only i915 currently supports something 
like that ATM.

Best regards
Thomas

> 
> An addition to the above sequence, if at any time either the kernel or userspace
> prints a message to the console; and at that time a fbdev is registered then fbcon
> will takeover as the console driver from the dummy driver and it will start drawing
> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> where printend while no fbdev was registered, then fbcon will takeover the console
> as soon as a fbdev gets registered.
> 
> So since we already have deferred-takeover in the fbcon code, I wonder what you
> mean when you are talking about "provide deferred takeover" for simplekms?
> 
> Regards,
> 
> Hans
> 
> 
> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> will delay using the fbdev until the VT is switched back to text mode.
> 
> 
> p.s.
> 
> This has the interesting side effect then when logging into a desktop GUI session:
> kernel -> plymouth -> gdm -> GNOME user session
> 
> There never is any output to the text-console and fbcon never takes-over, so on
> many Laptops running say Fedora workstation the fbcon code is actually unused
> until the user manually switches to another virtual-console to log in in
> text-mode:
> 
> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> [    0.258904] Console: colour dummy device 80x25
> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> [    1.274768] fbcon: Deferring console take-over
> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> [    2.540896] fbcon: Deferring console take-over
> [hans@x1 ~]$ uptime
>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> 
> Look mom no fbcon
> 
> 
> 
> 
>> 	* provide bootsplash DRM client
>> 	* make simplekms usable with ARM-EFI fbs
>>
>> v2:
>> 	* rename to simpledrm, aperture helpers
>> 	* reorganized patches
>> 	* use hotplug helpers for removal (Daniel)
>> 	* added DT match tables (Rob)
>> 	* use shadow-plane helpers
>> 	* lots of minor cleanups
>>
>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>
>> Thomas Zimmermann (10):
>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>    drm/format-helper: Add blitter functions
>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>    drm/aperture: Add infrastructure for aperture ownership
>>    drm: Add simpledrm driver
>>    drm/simpledrm: Add fbdev emulation
>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>    drm/simpledrm: Acquire clocks from DT device node
>>    drm/simpledrm: Acquire regulators from DT device node
>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>
>>   Documentation/gpu/drm-internals.rst    |  12 +
>>   MAINTAINERS                            |   7 +
>>   drivers/gpu/drm/Kconfig                |   7 +
>>   drivers/gpu/drm/Makefile               |   1 +
>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>   include/drm/drm_aperture.h             |  96 +++
>>   include/drm/drm_fb_helper.h            |  56 +-
>>   include/drm/drm_format_helper.h        |  10 +-
>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> --
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-29 12:31     ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-29 12:31 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc


[-- Attachment #1.1.1: Type: text/plain, Size: 9780 bytes --]

Hi

Am 25.03.21 um 12:29 schrieb Hans de Goede:
> Hi,
> 
> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>> This patchset adds support for simple-framebuffer platform devices and
>> a handover mechanism for native drivers to take-over control of the
>> hardware.
>>
>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>> device. The kernel's boot code creates such devices for firmware-provided
>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>> loader sets up the framebuffers. Description via device tree is also an
>> option.
>>
>> Simpledrm is small enough to be linked into the kernel. The driver's main
>> purpose is to provide graphical output during the early phases of the boot
>> process, before the native DRM drivers are available. Native drivers are
>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>> serve as interim solution on graphics hardware without native DRM driver.
>>
>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>> the drivers do not provide DRM interfaces for modern userspace.
>>
>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>
>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>> framebuffer's I/O-memory range and provides a callback function to be
>> removed by a native driver. The native driver will remove simpledrm before
>> taking over the hardware. The removal is integrated into existing helpers,
>> so drivers use it automatically.
>>
>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>> regulators. It's based on the simplefb drivers, but has been modified for
>> DRM.
> 
> Thank you for your work on this, this is very interesting.
> 
>> I've also been working on fastboot support (i.e., flicker-free booting).
>> This requires state-readout from simpledrm via generic interfaces, as
>> outlined in [1]. I do have some prototype code, but it will take a while
>> to get this ready. Simpledrm will then support it.
>>
>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>> reliably. The fbdev console and Weston work automatically. Xorg requires
>> manual configuration of the device. Xorgs current modesetting driver does
>> not work with both, platform and PCI device, for the same physical
>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>> I expect the problem to become a non-issue soon. Additional testing has
>> been reported at [2].
>>
>> One cosmetical issue is that simpledrm's device file is card0 and the
>> native driver's device file is card1. After simpledrm has been kicked out,
>> only card1 is left. This does not seem to be a practical problem however.
>>
>> TODO/IDEAS:
>>
>> 	* provide deferred takeover
> 
> I'm not sure what you mean with this ?  Currently deferred-takeover is
> handled in the fbcon code. Current flickerfree boot works like this
> (assuming a single LCD panel in a laptop):
> 
> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> 2. The bootloader runs in silent mode and does not touch anything gfx related
> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>     the console and leaves the dummy-console driver in place (unless there have already
>     been kernel messages logged, which there shouldn't because loglevel=3)
> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>     panel which it would set, they match, nothing happens. i915 takes ownership
>     of the scanout-buffer set up by the GOP, but leaves it in place.
>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>     console driver in place as console driver.
> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>     sees no changes, other then the spinner appearing
>     (note the active VT is now in graphical mode)
> 5. From here on not flickering is a userspace problem
> 
> AFAICT this should work fine with simplekms too, unless it clears the screen
> to black when it binds.

I forgot to add the code that clears the screen, but that's the case here.

Instead of a plane-disable operation, simpledrm can at best clear the 
screen. This would happen during the initial mode-config reset IIRC. But 
we need to keep the display content stored in a framebuffer, so read-out 
helpers are required. There are more users of these read-out helpers. 
Adding them at some point probably makes sense.

Other drivers might also want to read the initial config from simpledrm 
via read-out helpers. I think only i915 currently supports something 
like that ATM.

Best regards
Thomas

> 
> An addition to the above sequence, if at any time either the kernel or userspace
> prints a message to the console; and at that time a fbdev is registered then fbcon
> will takeover as the console driver from the dummy driver and it will start drawing
> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> where printend while no fbdev was registered, then fbcon will takeover the console
> as soon as a fbdev gets registered.
> 
> So since we already have deferred-takeover in the fbcon code, I wonder what you
> mean when you are talking about "provide deferred takeover" for simplekms?
> 
> Regards,
> 
> Hans
> 
> 
> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> will delay using the fbdev until the VT is switched back to text mode.
> 
> 
> p.s.
> 
> This has the interesting side effect then when logging into a desktop GUI session:
> kernel -> plymouth -> gdm -> GNOME user session
> 
> There never is any output to the text-console and fbcon never takes-over, so on
> many Laptops running say Fedora workstation the fbcon code is actually unused
> until the user manually switches to another virtual-console to log in in
> text-mode:
> 
> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> [    0.258904] Console: colour dummy device 80x25
> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> [    1.274768] fbcon: Deferring console take-over
> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> [    2.540896] fbcon: Deferring console take-over
> [hans@x1 ~]$ uptime
>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> 
> Look mom no fbcon
> 
> 
> 
> 
>> 	* provide bootsplash DRM client
>> 	* make simplekms usable with ARM-EFI fbs
>>
>> v2:
>> 	* rename to simpledrm, aperture helpers
>> 	* reorganized patches
>> 	* use hotplug helpers for removal (Daniel)
>> 	* added DT match tables (Rob)
>> 	* use shadow-plane helpers
>> 	* lots of minor cleanups
>>
>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>
>> Thomas Zimmermann (10):
>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>    drm/format-helper: Add blitter functions
>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>    drm/aperture: Add infrastructure for aperture ownership
>>    drm: Add simpledrm driver
>>    drm/simpledrm: Add fbdev emulation
>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>    drm/simpledrm: Acquire clocks from DT device node
>>    drm/simpledrm: Acquire regulators from DT device node
>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>
>>   Documentation/gpu/drm-internals.rst    |  12 +
>>   MAINTAINERS                            |   7 +
>>   drivers/gpu/drm/Kconfig                |   7 +
>>   drivers/gpu/drm/Makefile               |   1 +
>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>   include/drm/drm_aperture.h             |  96 +++
>>   include/drm/drm_fb_helper.h            |  56 +-
>>   include/drm/drm_format_helper.h        |  10 +-
>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> --
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-29 12:31     ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-29 12:31 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc


[-- Attachment #1.1.1: Type: text/plain, Size: 9780 bytes --]

Hi

Am 25.03.21 um 12:29 schrieb Hans de Goede:
> Hi,
> 
> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>> This patchset adds support for simple-framebuffer platform devices and
>> a handover mechanism for native drivers to take-over control of the
>> hardware.
>>
>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>> device. The kernel's boot code creates such devices for firmware-provided
>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>> loader sets up the framebuffers. Description via device tree is also an
>> option.
>>
>> Simpledrm is small enough to be linked into the kernel. The driver's main
>> purpose is to provide graphical output during the early phases of the boot
>> process, before the native DRM drivers are available. Native drivers are
>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>> serve as interim solution on graphics hardware without native DRM driver.
>>
>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>> the drivers do not provide DRM interfaces for modern userspace.
>>
>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>
>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>> framebuffer's I/O-memory range and provides a callback function to be
>> removed by a native driver. The native driver will remove simpledrm before
>> taking over the hardware. The removal is integrated into existing helpers,
>> so drivers use it automatically.
>>
>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>> regulators. It's based on the simplefb drivers, but has been modified for
>> DRM.
> 
> Thank you for your work on this, this is very interesting.
> 
>> I've also been working on fastboot support (i.e., flicker-free booting).
>> This requires state-readout from simpledrm via generic interfaces, as
>> outlined in [1]. I do have some prototype code, but it will take a while
>> to get this ready. Simpledrm will then support it.
>>
>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>> reliably. The fbdev console and Weston work automatically. Xorg requires
>> manual configuration of the device. Xorgs current modesetting driver does
>> not work with both, platform and PCI device, for the same physical
>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>> I expect the problem to become a non-issue soon. Additional testing has
>> been reported at [2].
>>
>> One cosmetical issue is that simpledrm's device file is card0 and the
>> native driver's device file is card1. After simpledrm has been kicked out,
>> only card1 is left. This does not seem to be a practical problem however.
>>
>> TODO/IDEAS:
>>
>> 	* provide deferred takeover
> 
> I'm not sure what you mean with this ?  Currently deferred-takeover is
> handled in the fbcon code. Current flickerfree boot works like this
> (assuming a single LCD panel in a laptop):
> 
> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> 2. The bootloader runs in silent mode and does not touch anything gfx related
> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>     the console and leaves the dummy-console driver in place (unless there have already
>     been kernel messages logged, which there shouldn't because loglevel=3)
> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>     panel which it would set, they match, nothing happens. i915 takes ownership
>     of the scanout-buffer set up by the GOP, but leaves it in place.
>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>     console driver in place as console driver.
> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>     sees no changes, other then the spinner appearing
>     (note the active VT is now in graphical mode)
> 5. From here on not flickering is a userspace problem
> 
> AFAICT this should work fine with simplekms too, unless it clears the screen
> to black when it binds.

I forgot to add the code that clears the screen, but that's the case here.

Instead of a plane-disable operation, simpledrm can at best clear the 
screen. This would happen during the initial mode-config reset IIRC. But 
we need to keep the display content stored in a framebuffer, so read-out 
helpers are required. There are more users of these read-out helpers. 
Adding them at some point probably makes sense.

Other drivers might also want to read the initial config from simpledrm 
via read-out helpers. I think only i915 currently supports something 
like that ATM.

Best regards
Thomas

> 
> An addition to the above sequence, if at any time either the kernel or userspace
> prints a message to the console; and at that time a fbdev is registered then fbcon
> will takeover as the console driver from the dummy driver and it will start drawing
> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> where printend while no fbdev was registered, then fbcon will takeover the console
> as soon as a fbdev gets registered.
> 
> So since we already have deferred-takeover in the fbcon code, I wonder what you
> mean when you are talking about "provide deferred takeover" for simplekms?
> 
> Regards,
> 
> Hans
> 
> 
> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> will delay using the fbdev until the VT is switched back to text mode.
> 
> 
> p.s.
> 
> This has the interesting side effect then when logging into a desktop GUI session:
> kernel -> plymouth -> gdm -> GNOME user session
> 
> There never is any output to the text-console and fbcon never takes-over, so on
> many Laptops running say Fedora workstation the fbcon code is actually unused
> until the user manually switches to another virtual-console to log in in
> text-mode:
> 
> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> [    0.258904] Console: colour dummy device 80x25
> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> [    1.274768] fbcon: Deferring console take-over
> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> [    2.540896] fbcon: Deferring console take-over
> [hans@x1 ~]$ uptime
>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> 
> Look mom no fbcon
> 
> 
> 
> 
>> 	* provide bootsplash DRM client
>> 	* make simplekms usable with ARM-EFI fbs
>>
>> v2:
>> 	* rename to simpledrm, aperture helpers
>> 	* reorganized patches
>> 	* use hotplug helpers for removal (Daniel)
>> 	* added DT match tables (Rob)
>> 	* use shadow-plane helpers
>> 	* lots of minor cleanups
>>
>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>
>> Thomas Zimmermann (10):
>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>    drm/format-helper: Add blitter functions
>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>    drm/aperture: Add infrastructure for aperture ownership
>>    drm: Add simpledrm driver
>>    drm/simpledrm: Add fbdev emulation
>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>    drm/simpledrm: Acquire clocks from DT device node
>>    drm/simpledrm: Acquire regulators from DT device node
>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>
>>   Documentation/gpu/drm-internals.rst    |  12 +
>>   MAINTAINERS                            |   7 +
>>   drivers/gpu/drm/Kconfig                |   7 +
>>   drivers/gpu/drm/Makefile               |   1 +
>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>   include/drm/drm_aperture.h             |  96 +++
>>   include/drm/drm_fb_helper.h            |  56 +-
>>   include/drm/drm_format_helper.h        |  10 +-
>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> --
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-29 12:31     ` Thomas Zimmermann
  (?)
@ 2021-03-29 14:50       ` Hans de Goede
  -1 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-29 14:50 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: dri-devel, linux-doc, virtualization

Hi,

On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> Hi
> 
> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>> This patchset adds support for simple-framebuffer platform devices and
>>> a handover mechanism for native drivers to take-over control of the
>>> hardware.
>>>
>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>> device. The kernel's boot code creates such devices for firmware-provided
>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>> loader sets up the framebuffers. Description via device tree is also an
>>> option.
>>>
>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>> purpose is to provide graphical output during the early phases of the boot
>>> process, before the native DRM drivers are available. Native drivers are
>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>> serve as interim solution on graphics hardware without native DRM driver.
>>>
>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>> the drivers do not provide DRM interfaces for modern userspace.
>>>
>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>
>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>> framebuffer's I/O-memory range and provides a callback function to be
>>> removed by a native driver. The native driver will remove simpledrm before
>>> taking over the hardware. The removal is integrated into existing helpers,
>>> so drivers use it automatically.
>>>
>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>> regulators. It's based on the simplefb drivers, but has been modified for
>>> DRM.
>>
>> Thank you for your work on this, this is very interesting.
>>
>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>> This requires state-readout from simpledrm via generic interfaces, as
>>> outlined in [1]. I do have some prototype code, but it will take a while
>>> to get this ready. Simpledrm will then support it.
>>>
>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>> manual configuration of the device. Xorgs current modesetting driver does
>>> not work with both, platform and PCI device, for the same physical
>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>> I expect the problem to become a non-issue soon. Additional testing has
>>> been reported at [2].
>>>
>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>> native driver's device file is card1. After simpledrm has been kicked out,
>>> only card1 is left. This does not seem to be a practical problem however.
>>>
>>> TODO/IDEAS:
>>>
>>>     * provide deferred takeover
>>
>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>> handled in the fbcon code. Current flickerfree boot works like this
>> (assuming a single LCD panel in a laptop):
>>
>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>     the console and leaves the dummy-console driver in place (unless there have already
>>     been kernel messages logged, which there shouldn't because loglevel=3)
>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>     panel which it would set, they match, nothing happens. i915 takes ownership
>>     of the scanout-buffer set up by the GOP, but leaves it in place.
>>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>>     console driver in place as console driver.
>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>     sees no changes, other then the spinner appearing
>>     (note the active VT is now in graphical mode)
>> 5. From here on not flickering is a userspace problem
>>
>> AFAICT this should work fine with simplekms too, unless it clears the screen
>> to black when it binds.
> 
> I forgot to add the code that clears the screen, but that's the case here.
> 
> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.

Hmm, clearing the screen without any (atomic) modesets being initiated by either
an in kernel drm-client or userspace seems wrong, this is certainly different from
what the i915 driver does. The way I see it either a drm client provides a new
framebuffer in which case you copy that over the old contents, effectively clearing
it. Or a drm-client gets a handle and draws to the current fb directly, in which
case it is the clients responsibility to clear it itself first.

IOW I believe that simpledrm should not clear the screen itself at all.

Regards,

Hans



> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> 
> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> 
> Best regards
> Thomas
> 
>>
>> An addition to the above sequence, if at any time either the kernel or userspace
>> prints a message to the console; and at that time a fbdev is registered then fbcon
>> will takeover as the console driver from the dummy driver and it will start drawing
>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>> where printend while no fbdev was registered, then fbcon will takeover the console
>> as soon as a fbdev gets registered.
>>
>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>> mean when you are talking about "provide deferred takeover" for simplekms?
>>
>> Regards,
>>
>> Hans
>>
>>
>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>> will delay using the fbdev until the VT is switched back to text mode.
>>
>>
>> p.s.
>>
>> This has the interesting side effect then when logging into a desktop GUI session:
>> kernel -> plymouth -> gdm -> GNOME user session
>>
>> There never is any output to the text-console and fbcon never takes-over, so on
>> many Laptops running say Fedora workstation the fbcon code is actually unused
>> until the user manually switches to another virtual-console to log in in
>> text-mode:
>>
>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>> [    0.258904] Console: colour dummy device 80x25
>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>> [    1.274768] fbcon: Deferring console take-over
>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>> [    2.540896] fbcon: Deferring console take-over
>> [hans@x1 ~]$ uptime
>>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>
>> Look mom no fbcon
>>
>>
>>
>>
>>>     * provide bootsplash DRM client
>>>     * make simplekms usable with ARM-EFI fbs
>>>
>>> v2:
>>>     * rename to simpledrm, aperture helpers
>>>     * reorganized patches
>>>     * use hotplug helpers for removal (Daniel)
>>>     * added DT match tables (Rob)
>>>     * use shadow-plane helpers
>>>     * lots of minor cleanups
>>>
>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>
>>> Thomas Zimmermann (10):
>>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>    drm/format-helper: Add blitter functions
>>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>    drm/aperture: Add infrastructure for aperture ownership
>>>    drm: Add simpledrm driver
>>>    drm/simpledrm: Add fbdev emulation
>>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>>    drm/simpledrm: Acquire clocks from DT device node
>>>    drm/simpledrm: Acquire regulators from DT device node
>>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>>
>>>   Documentation/gpu/drm-internals.rst    |  12 +
>>>   MAINTAINERS                            |   7 +
>>>   drivers/gpu/drm/Kconfig                |   7 +
>>>   drivers/gpu/drm/Makefile               |   1 +
>>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>   include/drm/drm_aperture.h             |  96 +++
>>>   include/drm/drm_fb_helper.h            |  56 +-
>>>   include/drm/drm_format_helper.h        |  10 +-
>>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>   create mode 100644 include/drm/drm_aperture.h
>>>
>>> -- 
>>> 2.30.1
>>>
>>
> 


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-29 14:50       ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-29 14:50 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc

Hi,

On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> Hi
> 
> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>> This patchset adds support for simple-framebuffer platform devices and
>>> a handover mechanism for native drivers to take-over control of the
>>> hardware.
>>>
>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>> device. The kernel's boot code creates such devices for firmware-provided
>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>> loader sets up the framebuffers. Description via device tree is also an
>>> option.
>>>
>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>> purpose is to provide graphical output during the early phases of the boot
>>> process, before the native DRM drivers are available. Native drivers are
>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>> serve as interim solution on graphics hardware without native DRM driver.
>>>
>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>> the drivers do not provide DRM interfaces for modern userspace.
>>>
>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>
>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>> framebuffer's I/O-memory range and provides a callback function to be
>>> removed by a native driver. The native driver will remove simpledrm before
>>> taking over the hardware. The removal is integrated into existing helpers,
>>> so drivers use it automatically.
>>>
>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>> regulators. It's based on the simplefb drivers, but has been modified for
>>> DRM.
>>
>> Thank you for your work on this, this is very interesting.
>>
>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>> This requires state-readout from simpledrm via generic interfaces, as
>>> outlined in [1]. I do have some prototype code, but it will take a while
>>> to get this ready. Simpledrm will then support it.
>>>
>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>> manual configuration of the device. Xorgs current modesetting driver does
>>> not work with both, platform and PCI device, for the same physical
>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>> I expect the problem to become a non-issue soon. Additional testing has
>>> been reported at [2].
>>>
>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>> native driver's device file is card1. After simpledrm has been kicked out,
>>> only card1 is left. This does not seem to be a practical problem however.
>>>
>>> TODO/IDEAS:
>>>
>>>     * provide deferred takeover
>>
>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>> handled in the fbcon code. Current flickerfree boot works like this
>> (assuming a single LCD panel in a laptop):
>>
>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>     the console and leaves the dummy-console driver in place (unless there have already
>>     been kernel messages logged, which there shouldn't because loglevel=3)
>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>     panel which it would set, they match, nothing happens. i915 takes ownership
>>     of the scanout-buffer set up by the GOP, but leaves it in place.
>>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>>     console driver in place as console driver.
>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>     sees no changes, other then the spinner appearing
>>     (note the active VT is now in graphical mode)
>> 5. From here on not flickering is a userspace problem
>>
>> AFAICT this should work fine with simplekms too, unless it clears the screen
>> to black when it binds.
> 
> I forgot to add the code that clears the screen, but that's the case here.
> 
> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.

Hmm, clearing the screen without any (atomic) modesets being initiated by either
an in kernel drm-client or userspace seems wrong, this is certainly different from
what the i915 driver does. The way I see it either a drm client provides a new
framebuffer in which case you copy that over the old contents, effectively clearing
it. Or a drm-client gets a handle and draws to the current fb directly, in which
case it is the clients responsibility to clear it itself first.

IOW I believe that simpledrm should not clear the screen itself at all.

Regards,

Hans



> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> 
> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> 
> Best regards
> Thomas
> 
>>
>> An addition to the above sequence, if at any time either the kernel or userspace
>> prints a message to the console; and at that time a fbdev is registered then fbcon
>> will takeover as the console driver from the dummy driver and it will start drawing
>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>> where printend while no fbdev was registered, then fbcon will takeover the console
>> as soon as a fbdev gets registered.
>>
>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>> mean when you are talking about "provide deferred takeover" for simplekms?
>>
>> Regards,
>>
>> Hans
>>
>>
>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>> will delay using the fbdev until the VT is switched back to text mode.
>>
>>
>> p.s.
>>
>> This has the interesting side effect then when logging into a desktop GUI session:
>> kernel -> plymouth -> gdm -> GNOME user session
>>
>> There never is any output to the text-console and fbcon never takes-over, so on
>> many Laptops running say Fedora workstation the fbcon code is actually unused
>> until the user manually switches to another virtual-console to log in in
>> text-mode:
>>
>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>> [    0.258904] Console: colour dummy device 80x25
>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>> [    1.274768] fbcon: Deferring console take-over
>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>> [    2.540896] fbcon: Deferring console take-over
>> [hans@x1 ~]$ uptime
>>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>
>> Look mom no fbcon
>>
>>
>>
>>
>>>     * provide bootsplash DRM client
>>>     * make simplekms usable with ARM-EFI fbs
>>>
>>> v2:
>>>     * rename to simpledrm, aperture helpers
>>>     * reorganized patches
>>>     * use hotplug helpers for removal (Daniel)
>>>     * added DT match tables (Rob)
>>>     * use shadow-plane helpers
>>>     * lots of minor cleanups
>>>
>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>
>>> Thomas Zimmermann (10):
>>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>    drm/format-helper: Add blitter functions
>>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>    drm/aperture: Add infrastructure for aperture ownership
>>>    drm: Add simpledrm driver
>>>    drm/simpledrm: Add fbdev emulation
>>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>>    drm/simpledrm: Acquire clocks from DT device node
>>>    drm/simpledrm: Acquire regulators from DT device node
>>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>>
>>>   Documentation/gpu/drm-internals.rst    |  12 +
>>>   MAINTAINERS                            |   7 +
>>>   drivers/gpu/drm/Kconfig                |   7 +
>>>   drivers/gpu/drm/Makefile               |   1 +
>>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>   include/drm/drm_aperture.h             |  96 +++
>>>   include/drm/drm_fb_helper.h            |  56 +-
>>>   include/drm/drm_format_helper.h        |  10 +-
>>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>   create mode 100644 include/drm/drm_aperture.h
>>>
>>> -- 
>>> 2.30.1
>>>
>>
> 

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-29 14:50       ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-29 14:50 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc

Hi,

On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> Hi
> 
> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>> This patchset adds support for simple-framebuffer platform devices and
>>> a handover mechanism for native drivers to take-over control of the
>>> hardware.
>>>
>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>> device. The kernel's boot code creates such devices for firmware-provided
>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>> loader sets up the framebuffers. Description via device tree is also an
>>> option.
>>>
>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>> purpose is to provide graphical output during the early phases of the boot
>>> process, before the native DRM drivers are available. Native drivers are
>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>> serve as interim solution on graphics hardware without native DRM driver.
>>>
>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>> the drivers do not provide DRM interfaces for modern userspace.
>>>
>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>
>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>> framebuffer's I/O-memory range and provides a callback function to be
>>> removed by a native driver. The native driver will remove simpledrm before
>>> taking over the hardware. The removal is integrated into existing helpers,
>>> so drivers use it automatically.
>>>
>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>> regulators. It's based on the simplefb drivers, but has been modified for
>>> DRM.
>>
>> Thank you for your work on this, this is very interesting.
>>
>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>> This requires state-readout from simpledrm via generic interfaces, as
>>> outlined in [1]. I do have some prototype code, but it will take a while
>>> to get this ready. Simpledrm will then support it.
>>>
>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>> manual configuration of the device. Xorgs current modesetting driver does
>>> not work with both, platform and PCI device, for the same physical
>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>> I expect the problem to become a non-issue soon. Additional testing has
>>> been reported at [2].
>>>
>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>> native driver's device file is card1. After simpledrm has been kicked out,
>>> only card1 is left. This does not seem to be a practical problem however.
>>>
>>> TODO/IDEAS:
>>>
>>>     * provide deferred takeover
>>
>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>> handled in the fbcon code. Current flickerfree boot works like this
>> (assuming a single LCD panel in a laptop):
>>
>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>     to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>     the console and leaves the dummy-console driver in place (unless there have already
>>     been kernel messages logged, which there shouldn't because loglevel=3)
>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>     panel which it would set, they match, nothing happens. i915 takes ownership
>>     of the scanout-buffer set up by the GOP, but leaves it in place.
>>     i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>     device, fbcon is notified of this, but is still deferred and leaves the dummy
>>     console driver in place as console driver.
>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>     plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>     scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>     scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>     sees no changes, other then the spinner appearing
>>     (note the active VT is now in graphical mode)
>> 5. From here on not flickering is a userspace problem
>>
>> AFAICT this should work fine with simplekms too, unless it clears the screen
>> to black when it binds.
> 
> I forgot to add the code that clears the screen, but that's the case here.
> 
> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.

Hmm, clearing the screen without any (atomic) modesets being initiated by either
an in kernel drm-client or userspace seems wrong, this is certainly different from
what the i915 driver does. The way I see it either a drm client provides a new
framebuffer in which case you copy that over the old contents, effectively clearing
it. Or a drm-client gets a handle and draws to the current fb directly, in which
case it is the clients responsibility to clear it itself first.

IOW I believe that simpledrm should not clear the screen itself at all.

Regards,

Hans



> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> 
> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> 
> Best regards
> Thomas
> 
>>
>> An addition to the above sequence, if at any time either the kernel or userspace
>> prints a message to the console; and at that time a fbdev is registered then fbcon
>> will takeover as the console driver from the dummy driver and it will start drawing
>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>> where printend while no fbdev was registered, then fbcon will takeover the console
>> as soon as a fbdev gets registered.
>>
>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>> mean when you are talking about "provide deferred takeover" for simplekms?
>>
>> Regards,
>>
>> Hans
>>
>>
>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>> will delay using the fbdev until the VT is switched back to text mode.
>>
>>
>> p.s.
>>
>> This has the interesting side effect then when logging into a desktop GUI session:
>> kernel -> plymouth -> gdm -> GNOME user session
>>
>> There never is any output to the text-console and fbcon never takes-over, so on
>> many Laptops running say Fedora workstation the fbcon code is actually unused
>> until the user manually switches to another virtual-console to log in in
>> text-mode:
>>
>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>> [    0.258904] Console: colour dummy device 80x25
>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>> [    1.274768] fbcon: Deferring console take-over
>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>> [    2.540896] fbcon: Deferring console take-over
>> [hans@x1 ~]$ uptime
>>   12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>
>> Look mom no fbcon
>>
>>
>>
>>
>>>     * provide bootsplash DRM client
>>>     * make simplekms usable with ARM-EFI fbs
>>>
>>> v2:
>>>     * rename to simpledrm, aperture helpers
>>>     * reorganized patches
>>>     * use hotplug helpers for removal (Daniel)
>>>     * added DT match tables (Rob)
>>>     * use shadow-plane helpers
>>>     * lots of minor cleanups
>>>
>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>
>>> Thomas Zimmermann (10):
>>>    drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>    drm/format-helper: Add blitter functions
>>>    drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>    drm/aperture: Add infrastructure for aperture ownership
>>>    drm: Add simpledrm driver
>>>    drm/simpledrm: Add fbdev emulation
>>>    drm/simpledrm: Initialize framebuffer data from device-tree node
>>>    drm/simpledrm: Acquire clocks from DT device node
>>>    drm/simpledrm: Acquire regulators from DT device node
>>>    drm/simpledrm: Acquire memory aperture for framebuffer
>>>
>>>   Documentation/gpu/drm-internals.rst    |  12 +
>>>   MAINTAINERS                            |   7 +
>>>   drivers/gpu/drm/Kconfig                |   7 +
>>>   drivers/gpu/drm/Makefile               |   1 +
>>>   drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>   drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>   drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>   drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>   drivers/gpu/drm/tiny/Makefile          |   1 +
>>>   drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>   drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>   include/drm/drm_aperture.h             |  96 +++
>>>   include/drm/drm_fb_helper.h            |  56 +-
>>>   include/drm/drm_format_helper.h        |  10 +-
>>>   14 files changed, 1466 insertions(+), 60 deletions(-)
>>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>   create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>   create mode 100644 include/drm/drm_aperture.h
>>>
>>> -- 
>>> 2.30.1
>>>
>>
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-29 14:50       ` Hans de Goede
  (?)
@ 2021-03-30  7:09         ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-30  7:09 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc


[-- Attachment #1.1: Type: text/plain, Size: 11794 bytes --]

Hi

Am 29.03.21 um 16:50 schrieb Hans de Goede:
> Hi,
> 
> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>> Hi,
>>>
>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>> This patchset adds support for simple-framebuffer platform devices and
>>>> a handover mechanism for native drivers to take-over control of the
>>>> hardware.
>>>>
>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>> loader sets up the framebuffers. Description via device tree is also an
>>>> option.
>>>>
>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>> purpose is to provide graphical output during the early phases of the boot
>>>> process, before the native DRM drivers are available. Native drivers are
>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>
>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>
>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>
>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>> removed by a native driver. The native driver will remove simpledrm before
>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>> so drivers use it automatically.
>>>>
>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>> DRM.
>>>
>>> Thank you for your work on this, this is very interesting.
>>>
>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>> to get this ready. Simpledrm will then support it.
>>>>
>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>> not work with both, platform and PCI device, for the same physical
>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>> been reported at [2].
>>>>
>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>
>>>> TODO/IDEAS:
>>>>
>>>>      * provide deferred takeover
>>>
>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>> handled in the fbcon code. Current flickerfree boot works like this
>>> (assuming a single LCD panel in a laptop):
>>>
>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>      console driver in place as console driver.
>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>      sees no changes, other then the spinner appearing
>>>      (note the active VT is now in graphical mode)
>>> 5. From here on not flickering is a userspace problem
>>>
>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>> to black when it binds.
>>
>> I forgot to add the code that clears the screen, but that's the case here.
>>
>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> 
> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> an in kernel drm-client or userspace seems wrong, this is certainly different from
> what the i915 driver does. The way I see it either a drm client provides a new
> framebuffer in which case you copy that over the old contents, effectively clearing
> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> case it is the clients responsibility to clear it itself first.
> 
> IOW I believe that simpledrm should not clear the screen itself at all.

I do as well. And when I boot with simpledrm + native driver it's 
flicker-free from what I can tell. But drm_mode_config_reset() is 
supposed to reset HW and software state. There could be some corner case 
where we'd have to clear the screen. For now, it should be fine.

BTW if you have the time I'd appreciate your review of the patchset.

Best regards
Thomas

> 
> Regards,
> 
> Hans
> 
> 
> 
>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>
>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>
>> Best regards
>> Thomas
>>
>>>
>>> An addition to the above sequence, if at any time either the kernel or userspace
>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>> will takeover as the console driver from the dummy driver and it will start drawing
>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>> as soon as a fbdev gets registered.
>>>
>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>
>>> Regards,
>>>
>>> Hans
>>>
>>>
>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>> will delay using the fbdev until the VT is switched back to text mode.
>>>
>>>
>>> p.s.
>>>
>>> This has the interesting side effect then when logging into a desktop GUI session:
>>> kernel -> plymouth -> gdm -> GNOME user session
>>>
>>> There never is any output to the text-console and fbcon never takes-over, so on
>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>> until the user manually switches to another virtual-console to log in in
>>> text-mode:
>>>
>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>> [    0.258904] Console: colour dummy device 80x25
>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>> [    1.274768] fbcon: Deferring console take-over
>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>> [    2.540896] fbcon: Deferring console take-over
>>> [hans@x1 ~]$ uptime
>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>
>>> Look mom no fbcon
>>>
>>>
>>>
>>>
>>>>      * provide bootsplash DRM client
>>>>      * make simplekms usable with ARM-EFI fbs
>>>>
>>>> v2:
>>>>      * rename to simpledrm, aperture helpers
>>>>      * reorganized patches
>>>>      * use hotplug helpers for removal (Daniel)
>>>>      * added DT match tables (Rob)
>>>>      * use shadow-plane helpers
>>>>      * lots of minor cleanups
>>>>
>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>
>>>> Thomas Zimmermann (10):
>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>     drm/format-helper: Add blitter functions
>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>     drm: Add simpledrm driver
>>>>     drm/simpledrm: Add fbdev emulation
>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>
>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>    MAINTAINERS                            |   7 +
>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-30  7:09         ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-30  7:09 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: linux-doc, dri-devel, virtualization


[-- Attachment #1.1.1: Type: text/plain, Size: 11794 bytes --]

Hi

Am 29.03.21 um 16:50 schrieb Hans de Goede:
> Hi,
> 
> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>> Hi,
>>>
>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>> This patchset adds support for simple-framebuffer platform devices and
>>>> a handover mechanism for native drivers to take-over control of the
>>>> hardware.
>>>>
>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>> loader sets up the framebuffers. Description via device tree is also an
>>>> option.
>>>>
>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>> purpose is to provide graphical output during the early phases of the boot
>>>> process, before the native DRM drivers are available. Native drivers are
>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>
>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>
>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>
>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>> removed by a native driver. The native driver will remove simpledrm before
>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>> so drivers use it automatically.
>>>>
>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>> DRM.
>>>
>>> Thank you for your work on this, this is very interesting.
>>>
>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>> to get this ready. Simpledrm will then support it.
>>>>
>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>> not work with both, platform and PCI device, for the same physical
>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>> been reported at [2].
>>>>
>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>
>>>> TODO/IDEAS:
>>>>
>>>>      * provide deferred takeover
>>>
>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>> handled in the fbcon code. Current flickerfree boot works like this
>>> (assuming a single LCD panel in a laptop):
>>>
>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>      console driver in place as console driver.
>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>      sees no changes, other then the spinner appearing
>>>      (note the active VT is now in graphical mode)
>>> 5. From here on not flickering is a userspace problem
>>>
>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>> to black when it binds.
>>
>> I forgot to add the code that clears the screen, but that's the case here.
>>
>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> 
> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> an in kernel drm-client or userspace seems wrong, this is certainly different from
> what the i915 driver does. The way I see it either a drm client provides a new
> framebuffer in which case you copy that over the old contents, effectively clearing
> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> case it is the clients responsibility to clear it itself first.
> 
> IOW I believe that simpledrm should not clear the screen itself at all.

I do as well. And when I boot with simpledrm + native driver it's 
flicker-free from what I can tell. But drm_mode_config_reset() is 
supposed to reset HW and software state. There could be some corner case 
where we'd have to clear the screen. For now, it should be fine.

BTW if you have the time I'd appreciate your review of the patchset.

Best regards
Thomas

> 
> Regards,
> 
> Hans
> 
> 
> 
>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>
>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>
>> Best regards
>> Thomas
>>
>>>
>>> An addition to the above sequence, if at any time either the kernel or userspace
>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>> will takeover as the console driver from the dummy driver and it will start drawing
>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>> as soon as a fbdev gets registered.
>>>
>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>
>>> Regards,
>>>
>>> Hans
>>>
>>>
>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>> will delay using the fbdev until the VT is switched back to text mode.
>>>
>>>
>>> p.s.
>>>
>>> This has the interesting side effect then when logging into a desktop GUI session:
>>> kernel -> plymouth -> gdm -> GNOME user session
>>>
>>> There never is any output to the text-console and fbcon never takes-over, so on
>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>> until the user manually switches to another virtual-console to log in in
>>> text-mode:
>>>
>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>> [    0.258904] Console: colour dummy device 80x25
>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>> [    1.274768] fbcon: Deferring console take-over
>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>> [    2.540896] fbcon: Deferring console take-over
>>> [hans@x1 ~]$ uptime
>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>
>>> Look mom no fbcon
>>>
>>>
>>>
>>>
>>>>      * provide bootsplash DRM client
>>>>      * make simplekms usable with ARM-EFI fbs
>>>>
>>>> v2:
>>>>      * rename to simpledrm, aperture helpers
>>>>      * reorganized patches
>>>>      * use hotplug helpers for removal (Daniel)
>>>>      * added DT match tables (Rob)
>>>>      * use shadow-plane helpers
>>>>      * lots of minor cleanups
>>>>
>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>
>>>> Thomas Zimmermann (10):
>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>     drm/format-helper: Add blitter functions
>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>     drm: Add simpledrm driver
>>>>     drm/simpledrm: Add fbdev emulation
>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>
>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>    MAINTAINERS                            |   7 +
>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-30  7:09         ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-03-30  7:09 UTC (permalink / raw)
  To: Hans de Goede, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: linux-doc, dri-devel, virtualization


[-- Attachment #1.1.1: Type: text/plain, Size: 11794 bytes --]

Hi

Am 29.03.21 um 16:50 schrieb Hans de Goede:
> Hi,
> 
> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>> Hi,
>>>
>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>> This patchset adds support for simple-framebuffer platform devices and
>>>> a handover mechanism for native drivers to take-over control of the
>>>> hardware.
>>>>
>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>> loader sets up the framebuffers. Description via device tree is also an
>>>> option.
>>>>
>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>> purpose is to provide graphical output during the early phases of the boot
>>>> process, before the native DRM drivers are available. Native drivers are
>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>
>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>
>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>
>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>> removed by a native driver. The native driver will remove simpledrm before
>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>> so drivers use it automatically.
>>>>
>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>> DRM.
>>>
>>> Thank you for your work on this, this is very interesting.
>>>
>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>> to get this ready. Simpledrm will then support it.
>>>>
>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>> not work with both, platform and PCI device, for the same physical
>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>> been reported at [2].
>>>>
>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>
>>>> TODO/IDEAS:
>>>>
>>>>      * provide deferred takeover
>>>
>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>> handled in the fbcon code. Current flickerfree boot works like this
>>> (assuming a single LCD panel in a laptop):
>>>
>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>      console driver in place as console driver.
>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>      sees no changes, other then the spinner appearing
>>>      (note the active VT is now in graphical mode)
>>> 5. From here on not flickering is a userspace problem
>>>
>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>> to black when it binds.
>>
>> I forgot to add the code that clears the screen, but that's the case here.
>>
>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> 
> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> an in kernel drm-client or userspace seems wrong, this is certainly different from
> what the i915 driver does. The way I see it either a drm client provides a new
> framebuffer in which case you copy that over the old contents, effectively clearing
> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> case it is the clients responsibility to clear it itself first.
> 
> IOW I believe that simpledrm should not clear the screen itself at all.

I do as well. And when I boot with simpledrm + native driver it's 
flicker-free from what I can tell. But drm_mode_config_reset() is 
supposed to reset HW and software state. There could be some corner case 
where we'd have to clear the screen. For now, it should be fine.

BTW if you have the time I'd appreciate your review of the patchset.

Best regards
Thomas

> 
> Regards,
> 
> Hans
> 
> 
> 
>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>
>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>
>> Best regards
>> Thomas
>>
>>>
>>> An addition to the above sequence, if at any time either the kernel or userspace
>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>> will takeover as the console driver from the dummy driver and it will start drawing
>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>> as soon as a fbdev gets registered.
>>>
>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>
>>> Regards,
>>>
>>> Hans
>>>
>>>
>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>> will delay using the fbdev until the VT is switched back to text mode.
>>>
>>>
>>> p.s.
>>>
>>> This has the interesting side effect then when logging into a desktop GUI session:
>>> kernel -> plymouth -> gdm -> GNOME user session
>>>
>>> There never is any output to the text-console and fbcon never takes-over, so on
>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>> until the user manually switches to another virtual-console to log in in
>>> text-mode:
>>>
>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>> [    0.258904] Console: colour dummy device 80x25
>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>> [    1.274768] fbcon: Deferring console take-over
>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>> [    2.540896] fbcon: Deferring console take-over
>>> [hans@x1 ~]$ uptime
>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>
>>> Look mom no fbcon
>>>
>>>
>>>
>>>
>>>>      * provide bootsplash DRM client
>>>>      * make simplekms usable with ARM-EFI fbs
>>>>
>>>> v2:
>>>>      * rename to simpledrm, aperture helpers
>>>>      * reorganized patches
>>>>      * use hotplug helpers for removal (Daniel)
>>>>      * added DT match tables (Rob)
>>>>      * use shadow-plane helpers
>>>>      * lots of minor cleanups
>>>>
>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>
>>>> Thomas Zimmermann (10):
>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>     drm/format-helper: Add blitter functions
>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>     drm: Add simpledrm driver
>>>>     drm/simpledrm: Add fbdev emulation
>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>
>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>    MAINTAINERS                            |   7 +
>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-30  7:09         ` Thomas Zimmermann
  (?)
@ 2021-03-30  8:34           ` Hans de Goede
  -1 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-30  8:34 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: virtualization, dri-devel, linux-doc

Hi,

On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> Hi
> 
> Am 29.03.21 um 16:50 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>>> Hi
>>>
>>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>>> Hi,
>>>>
>>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>>> This patchset adds support for simple-framebuffer platform devices and
>>>>> a handover mechanism for native drivers to take-over control of the
>>>>> hardware.
>>>>>
>>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>>> loader sets up the framebuffers. Description via device tree is also an
>>>>> option.
>>>>>
>>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>>> purpose is to provide graphical output during the early phases of the boot
>>>>> process, before the native DRM drivers are available. Native drivers are
>>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>>
>>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>>
>>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>>
>>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>>> removed by a native driver. The native driver will remove simpledrm before
>>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>>> so drivers use it automatically.
>>>>>
>>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>>> DRM.
>>>>
>>>> Thank you for your work on this, this is very interesting.
>>>>
>>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>>> to get this ready. Simpledrm will then support it.
>>>>>
>>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>>> not work with both, platform and PCI device, for the same physical
>>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>>> been reported at [2].
>>>>>
>>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>>
>>>>> TODO/IDEAS:
>>>>>
>>>>>      * provide deferred takeover
>>>>
>>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>>> handled in the fbcon code. Current flickerfree boot works like this
>>>> (assuming a single LCD panel in a laptop):
>>>>
>>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>>      console driver in place as console driver.
>>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>>      sees no changes, other then the spinner appearing
>>>>      (note the active VT is now in graphical mode)
>>>> 5. From here on not flickering is a userspace problem
>>>>
>>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>>> to black when it binds.
>>>
>>> I forgot to add the code that clears the screen, but that's the case here.
>>>
>>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
>>
>> Hmm, clearing the screen without any (atomic) modesets being initiated by either
>> an in kernel drm-client or userspace seems wrong, this is certainly different from
>> what the i915 driver does. The way I see it either a drm client provides a new
>> framebuffer in which case you copy that over the old contents, effectively clearing
>> it. Or a drm-client gets a handle and draws to the current fb directly, in which
>> case it is the clients responsibility to clear it itself first.
>>
>> IOW I believe that simpledrm should not clear the screen itself at all.
> 
> I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.

Sounds good, thanks.

> BTW if you have the time I'd appreciate your review of the patchset.

Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.

Regards,

Hans





>>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>>
>>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>>
>>> Best regards
>>> Thomas
>>>
>>>>
>>>> An addition to the above sequence, if at any time either the kernel or userspace
>>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>>> will takeover as the console driver from the dummy driver and it will start drawing
>>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>>> as soon as a fbdev gets registered.
>>>>
>>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>>
>>>> Regards,
>>>>
>>>> Hans
>>>>
>>>>
>>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>>> will delay using the fbdev until the VT is switched back to text mode.
>>>>
>>>>
>>>> p.s.
>>>>
>>>> This has the interesting side effect then when logging into a desktop GUI session:
>>>> kernel -> plymouth -> gdm -> GNOME user session
>>>>
>>>> There never is any output to the text-console and fbcon never takes-over, so on
>>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>>> until the user manually switches to another virtual-console to log in in
>>>> text-mode:
>>>>
>>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>>> [    0.258904] Console: colour dummy device 80x25
>>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>>> [    1.274768] fbcon: Deferring console take-over
>>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>>> [    2.540896] fbcon: Deferring console take-over
>>>> [hans@x1 ~]$ uptime
>>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>>
>>>> Look mom no fbcon
>>>>
>>>>
>>>>
>>>>
>>>>>      * provide bootsplash DRM client
>>>>>      * make simplekms usable with ARM-EFI fbs
>>>>>
>>>>> v2:
>>>>>      * rename to simpledrm, aperture helpers
>>>>>      * reorganized patches
>>>>>      * use hotplug helpers for removal (Daniel)
>>>>>      * added DT match tables (Rob)
>>>>>      * use shadow-plane helpers
>>>>>      * lots of minor cleanups
>>>>>
>>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>>
>>>>> Thomas Zimmermann (10):
>>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>>     drm/format-helper: Add blitter functions
>>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>>     drm: Add simpledrm driver
>>>>>     drm/simpledrm: Add fbdev emulation
>>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>>
>>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>>    MAINTAINERS                            |   7 +
>>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>>
>>>>> -- 
>>>>> 2.30.1
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> 


^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-30  8:34           ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-30  8:34 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: linux-doc, dri-devel, virtualization

Hi,

On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> Hi
> 
> Am 29.03.21 um 16:50 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>>> Hi
>>>
>>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>>> Hi,
>>>>
>>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>>> This patchset adds support for simple-framebuffer platform devices and
>>>>> a handover mechanism for native drivers to take-over control of the
>>>>> hardware.
>>>>>
>>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>>> loader sets up the framebuffers. Description via device tree is also an
>>>>> option.
>>>>>
>>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>>> purpose is to provide graphical output during the early phases of the boot
>>>>> process, before the native DRM drivers are available. Native drivers are
>>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>>
>>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>>
>>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>>
>>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>>> removed by a native driver. The native driver will remove simpledrm before
>>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>>> so drivers use it automatically.
>>>>>
>>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>>> DRM.
>>>>
>>>> Thank you for your work on this, this is very interesting.
>>>>
>>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>>> to get this ready. Simpledrm will then support it.
>>>>>
>>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>>> not work with both, platform and PCI device, for the same physical
>>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>>> been reported at [2].
>>>>>
>>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>>
>>>>> TODO/IDEAS:
>>>>>
>>>>>      * provide deferred takeover
>>>>
>>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>>> handled in the fbcon code. Current flickerfree boot works like this
>>>> (assuming a single LCD panel in a laptop):
>>>>
>>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>>      console driver in place as console driver.
>>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>>      sees no changes, other then the spinner appearing
>>>>      (note the active VT is now in graphical mode)
>>>> 5. From here on not flickering is a userspace problem
>>>>
>>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>>> to black when it binds.
>>>
>>> I forgot to add the code that clears the screen, but that's the case here.
>>>
>>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
>>
>> Hmm, clearing the screen without any (atomic) modesets being initiated by either
>> an in kernel drm-client or userspace seems wrong, this is certainly different from
>> what the i915 driver does. The way I see it either a drm client provides a new
>> framebuffer in which case you copy that over the old contents, effectively clearing
>> it. Or a drm-client gets a handle and draws to the current fb directly, in which
>> case it is the clients responsibility to clear it itself first.
>>
>> IOW I believe that simpledrm should not clear the screen itself at all.
> 
> I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.

Sounds good, thanks.

> BTW if you have the time I'd appreciate your review of the patchset.

Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.

Regards,

Hans





>>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>>
>>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>>
>>> Best regards
>>> Thomas
>>>
>>>>
>>>> An addition to the above sequence, if at any time either the kernel or userspace
>>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>>> will takeover as the console driver from the dummy driver and it will start drawing
>>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>>> as soon as a fbdev gets registered.
>>>>
>>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>>
>>>> Regards,
>>>>
>>>> Hans
>>>>
>>>>
>>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>>> will delay using the fbdev until the VT is switched back to text mode.
>>>>
>>>>
>>>> p.s.
>>>>
>>>> This has the interesting side effect then when logging into a desktop GUI session:
>>>> kernel -> plymouth -> gdm -> GNOME user session
>>>>
>>>> There never is any output to the text-console and fbcon never takes-over, so on
>>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>>> until the user manually switches to another virtual-console to log in in
>>>> text-mode:
>>>>
>>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>>> [    0.258904] Console: colour dummy device 80x25
>>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>>> [    1.274768] fbcon: Deferring console take-over
>>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>>> [    2.540896] fbcon: Deferring console take-over
>>>> [hans@x1 ~]$ uptime
>>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>>
>>>> Look mom no fbcon
>>>>
>>>>
>>>>
>>>>
>>>>>      * provide bootsplash DRM client
>>>>>      * make simplekms usable with ARM-EFI fbs
>>>>>
>>>>> v2:
>>>>>      * rename to simpledrm, aperture helpers
>>>>>      * reorganized patches
>>>>>      * use hotplug helpers for removal (Daniel)
>>>>>      * added DT match tables (Rob)
>>>>>      * use shadow-plane helpers
>>>>>      * lots of minor cleanups
>>>>>
>>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>>
>>>>> Thomas Zimmermann (10):
>>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>>     drm/format-helper: Add blitter functions
>>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>>     drm: Add simpledrm driver
>>>>>     drm/simpledrm: Add fbdev emulation
>>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>>
>>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>>    MAINTAINERS                            |   7 +
>>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>>
>>>>> -- 
>>>>> 2.30.1
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> 

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-03-30  8:34           ` Hans de Goede
  0 siblings, 0 replies; 103+ messages in thread
From: Hans de Goede @ 2021-03-30  8:34 UTC (permalink / raw)
  To: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger
  Cc: linux-doc, dri-devel, virtualization

Hi,

On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> Hi
> 
> Am 29.03.21 um 16:50 schrieb Hans de Goede:
>> Hi,
>>
>> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
>>> Hi
>>>
>>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
>>>> Hi,
>>>>
>>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
>>>>> This patchset adds support for simple-framebuffer platform devices and
>>>>> a handover mechanism for native drivers to take-over control of the
>>>>> hardware.
>>>>>
>>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
>>>>> device. The kernel's boot code creates such devices for firmware-provided
>>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
>>>>> loader sets up the framebuffers. Description via device tree is also an
>>>>> option.
>>>>>
>>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
>>>>> purpose is to provide graphical output during the early phases of the boot
>>>>> process, before the native DRM drivers are available. Native drivers are
>>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
>>>>> serve as interim solution on graphics hardware without native DRM driver.
>>>>>
>>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
>>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
>>>>> the drivers do not provide DRM interfaces for modern userspace.
>>>>>
>>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
>>>>>
>>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
>>>>> framebuffer's I/O-memory range and provides a callback function to be
>>>>> removed by a native driver. The native driver will remove simpledrm before
>>>>> taking over the hardware. The removal is integrated into existing helpers,
>>>>> so drivers use it automatically.
>>>>>
>>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
>>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
>>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
>>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
>>>>> regulators. It's based on the simplefb drivers, but has been modified for
>>>>> DRM.
>>>>
>>>> Thank you for your work on this, this is very interesting.
>>>>
>>>>> I've also been working on fastboot support (i.e., flicker-free booting).
>>>>> This requires state-readout from simpledrm via generic interfaces, as
>>>>> outlined in [1]. I do have some prototype code, but it will take a while
>>>>> to get this ready. Simpledrm will then support it.
>>>>>
>>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
>>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
>>>>> manual configuration of the device. Xorgs current modesetting driver does
>>>>> not work with both, platform and PCI device, for the same physical
>>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
>>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
>>>>> I expect the problem to become a non-issue soon. Additional testing has
>>>>> been reported at [2].
>>>>>
>>>>> One cosmetical issue is that simpledrm's device file is card0 and the
>>>>> native driver's device file is card1. After simpledrm has been kicked out,
>>>>> only card1 is left. This does not seem to be a practical problem however.
>>>>>
>>>>> TODO/IDEAS:
>>>>>
>>>>>      * provide deferred takeover
>>>>
>>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
>>>> handled in the fbcon code. Current flickerfree boot works like this
>>>> (assuming a single LCD panel in a laptop):
>>>>
>>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
>>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
>>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
>>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
>>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
>>>>      the console and leaves the dummy-console driver in place (unless there have already
>>>>      been kernel messages logged, which there shouldn't because loglevel=3)
>>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
>>>>      panel which it would set, they match, nothing happens. i915 takes ownership
>>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
>>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
>>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
>>>>      console driver in place as console driver.
>>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
>>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
>>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
>>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
>>>>      sees no changes, other then the spinner appearing
>>>>      (note the active VT is now in graphical mode)
>>>> 5. From here on not flickering is a userspace problem
>>>>
>>>> AFAICT this should work fine with simplekms too, unless it clears the screen
>>>> to black when it binds.
>>>
>>> I forgot to add the code that clears the screen, but that's the case here.
>>>
>>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
>>
>> Hmm, clearing the screen without any (atomic) modesets being initiated by either
>> an in kernel drm-client or userspace seems wrong, this is certainly different from
>> what the i915 driver does. The way I see it either a drm client provides a new
>> framebuffer in which case you copy that over the old contents, effectively clearing
>> it. Or a drm-client gets a handle and draws to the current fb directly, in which
>> case it is the clients responsibility to clear it itself first.
>>
>> IOW I believe that simpledrm should not clear the screen itself at all.
> 
> I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.

Sounds good, thanks.

> BTW if you have the time I'd appreciate your review of the patchset.

Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.

Regards,

Hans





>>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
>>>
>>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
>>>
>>> Best regards
>>> Thomas
>>>
>>>>
>>>> An addition to the above sequence, if at any time either the kernel or userspace
>>>> prints a message to the console; and at that time a fbdev is registered then fbcon
>>>> will takeover as the console driver from the dummy driver and it will start drawing
>>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
>>>> where printend while no fbdev was registered, then fbcon will takeover the console
>>>> as soon as a fbdev gets registered.
>>>>
>>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
>>>> mean when you are talking about "provide deferred takeover" for simplekms?
>>>>
>>>> Regards,
>>>>
>>>> Hans
>>>>
>>>>
>>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
>>>> will delay using the fbdev until the VT is switched back to text mode.
>>>>
>>>>
>>>> p.s.
>>>>
>>>> This has the interesting side effect then when logging into a desktop GUI session:
>>>> kernel -> plymouth -> gdm -> GNOME user session
>>>>
>>>> There never is any output to the text-console and fbcon never takes-over, so on
>>>> many Laptops running say Fedora workstation the fbcon code is actually unused
>>>> until the user manually switches to another virtual-console to log in in
>>>> text-mode:
>>>>
>>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
>>>> [    0.258904] Console: colour dummy device 80x25
>>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
>>>> [    1.274768] fbcon: Deferring console take-over
>>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
>>>> [    2.540896] fbcon: Deferring console take-over
>>>> [hans@x1 ~]$ uptime
>>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
>>>>
>>>> Look mom no fbcon
>>>>
>>>>
>>>>
>>>>
>>>>>      * provide bootsplash DRM client
>>>>>      * make simplekms usable with ARM-EFI fbs
>>>>>
>>>>> v2:
>>>>>      * rename to simpledrm, aperture helpers
>>>>>      * reorganized patches
>>>>>      * use hotplug helpers for removal (Daniel)
>>>>>      * added DT match tables (Rob)
>>>>>      * use shadow-plane helpers
>>>>>      * lots of minor cleanups
>>>>>
>>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
>>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
>>>>>
>>>>> Thomas Zimmermann (10):
>>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
>>>>>     drm/format-helper: Add blitter functions
>>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
>>>>>     drm/aperture: Add infrastructure for aperture ownership
>>>>>     drm: Add simpledrm driver
>>>>>     drm/simpledrm: Add fbdev emulation
>>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
>>>>>     drm/simpledrm: Acquire clocks from DT device node
>>>>>     drm/simpledrm: Acquire regulators from DT device node
>>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
>>>>>
>>>>>    Documentation/gpu/drm-internals.rst    |  12 +
>>>>>    MAINTAINERS                            |   7 +
>>>>>    drivers/gpu/drm/Kconfig                |   7 +
>>>>>    drivers/gpu/drm/Makefile               |   1 +
>>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
>>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
>>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
>>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
>>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
>>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
>>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
>>>>>    include/drm/drm_aperture.h             |  96 +++
>>>>>    include/drm/drm_fb_helper.h            |  56 +-
>>>>>    include/drm/drm_format_helper.h        |  10 +-
>>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
>>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
>>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
>>>>>    create mode 100644 include/drm/drm_aperture.h
>>>>>
>>>>> -- 
>>>>> 2.30.1
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-03-18 10:29   ` Thomas Zimmermann
@ 2021-04-08  8:13     ` Maxime Ripard
  -1 siblings, 0 replies; 103+ messages in thread
From: Maxime Ripard @ 2021-04-08  8:13 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: daniel, airlied, maarten.lankhorst, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization

[-- Attachment #1: Type: text/plain, Size: 814 bytes --]

Hi,

On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> Make sure required hardware clocks are enabled while the firmware
> framebuffer is in use.
> 
> The basic code has been taken from the simplefb driver and adapted
> to DRM. Clocks are released automatically via devres helpers.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Even though it's definitely simpler to review, merging the driver first
and then the clocks and regulators will break bisection on the platforms
that rely on them

Another thing worth considering is also that both drivers will probe if
they are enabled (which is pretty likely), which is not great :)

I guess we should make them mutually exclusive through Kconfig

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-08  8:13     ` Maxime Ripard
  0 siblings, 0 replies; 103+ messages in thread
From: Maxime Ripard @ 2021-04-08  8:13 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, lgirdwood, dri-devel, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 814 bytes --]

Hi,

On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> Make sure required hardware clocks are enabled while the firmware
> framebuffer is in use.
> 
> The basic code has been taken from the simplefb driver and adapted
> to DRM. Clocks are released automatically via devres helpers.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Even though it's definitely simpler to review, merging the driver first
and then the clocks and regulators will break bisection on the platforms
that rely on them

Another thing worth considering is also that both drivers will probe if
they are enabled (which is pretty likely), which is not great :)

I guess we should make them mutually exclusive through Kconfig

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-03-18 10:29   ` Thomas Zimmermann
  (?)
@ 2021-04-08  9:48     ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger, dri-devel, linux-doc,
	virtualization

On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> Platform devices might operate on firmware framebuffers, such as VESA or
> EFI. Before a native driver for the graphics hardware can take over the
> device, it has to remove any platform driver that operates on the firmware
> framebuffer. Aperture helpers provide the infrastructure for platform
> drivers to acquire firmware framebuffers, and for native drivers to remove
> them later on.
> 
> It works similar to the related fbdev mechanism. During initialization, the
> platform driver acquires the firmware framebuffer's I/O memory and provides
> a callback to be removed. The native driver later uses this information to
> remove any platform driver for it's framebuffer I/O memory.
> 
> The aperture removal code is integrated into the existing code for removing
> conflicting framebuffers, so native drivers use it automatically.
> 
> v2:
> 	* rename plaform helpers to aperture helpers
> 	* tie to device lifetime with devm_ functions
> 	* removed unsued remove() callback
> 	* rename kickout to detach
> 	* make struct drm_aperture private
> 	* rebase onto existing drm_aperture.h header file
> 	* use MIT license only for simplicity
> 	* documentation
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Bunch of bikesheds for your considerations below, but overall lgtm.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Cheers, Daniel

> ---
>  Documentation/gpu/drm-internals.rst |   6 +
>  drivers/gpu/drm/Kconfig             |   7 +
>  drivers/gpu/drm/Makefile            |   1 +
>  drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>  include/drm/drm_aperture.h          |  38 +++-
>  5 files changed, 338 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 4c7642d2ca34..06af044c882f 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>  Managing Ownership of the Framebuffer Aperture
>  ----------------------------------------------
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :doc: overview
> +
>  .. kernel-doc:: include/drm/drm_aperture.h
>     :internal:
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :export:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 1461652921be..b9d3fb91d22d 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -221,6 +221,13 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_APERTURE
> +	bool
> +	depends on DRM
> +	help
> +	  Controls ownership of graphics apertures. Required to
> +	  synchronize with firmware-based drivers.

Uh I'm not a big fan of Kconfig and .ko modules for every little helper
code. Imo just stuff this into the drm kms helpers and done. Or stuff it
into drm core code, I think either is a good case for this. Everything is
its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
get funny ideas about using these internals ...

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 5eb5bf7c16e3..c9ecb02df0f3 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_PCI) += drm_pci.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o
>  obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> new file mode 100644
> index 000000000000..4b02b5fed0a1
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_aperture.c
> @@ -0,0 +1,287 @@
> +// SPDX-License-Identifier: MIT
> +
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_aperture.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * DOC: overview
> + *
> + * A graphics device might be supported by different drivers, but only one
> + * driver can be active at any given time. Many systems load a generic
> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> + * During later boot stages, they replace the generic driver with a dedicated,
> + * hardware-specific driver. To take over the device the dedicated driver
> + * first has to remove the generic driver. DRM aperture functions manage
> + * ownership of DRM framebuffer memory and hand-over between drivers.
> + *
> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> + * at the top of their probe function. The function removes any generic
> + * driver that is currently associated with the given framebuffer memory.
> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> + * example given below.
> + *
> + * .. code-block:: c
> + *
> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> + *	{
> + *		struct apertures_struct *ap;
> + *		bool primary = false;
> + *		int ret;
> + *
> + *		ap = alloc_apertures(1);
> + *		if (!ap)
> + *			return -ENOMEM;
> + *
> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> + *
> + *	#ifdef CONFIG_X86
> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> + *	#endif
> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> + *		kfree(ap);
> + *
> + *		return ret;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = remove_conflicting_framebuffers(pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> + * and let it detect the framebuffer apertures automatically.

Maybe just me, but to avoid overstretching the attention spawn of doc
readers I'd avoid this example here. And maybe make the recommendation
stronger, e.g. "PCI device drivers can avoid open-coding
remove_conflicting_framebuffers() by calling
drm_fb_helper_remove_conflicting_pci_framebuffers()."

> + *
> + * .. code-block:: c
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * Drivers that are susceptible to being removed be other drivers, such as
> + * generic EFI or VESA drivers, have to register themselves as owners of their
> + * given framebuffer memory. Ownership of the framebuffer memory is achived
> + * by calling devm_aperture_acquire(). On success, the driver is the owner
> + * of the framebuffer range. The function fails if the framebuffer is already
> + * by another driver. See below for an example.
> + *
> + * .. code-block:: c
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = ...

Is there really value in allowing/forcing drivers to set up their own
detach ops? You already make this specific to struct drm_device, an
implementation that just calls drm_dev_unplug feels like the right thing
to do?

Or maybe we should tie this more into the struct device mode and force an
unload that way? That way devm cleanup would work as one expects, and
avoid the need for anything specific (hopefully) in this detach callback.

Just feels a bit like we're reinventing half of the driver model here,
badly.

> + *	};
> + *
> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> + *	{
> + *		resource_size_t start, len;
> + *		struct drm_aperture *ap;
> + *
> + *		base = pci_resource_start(pdev, 0);
> + *		size = pci_resource_len(pdev, 0);
> + *
> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> + *		if (IS_ERR(ap))
> + *			return PTR_ERR(ap);
> + *
> + *		return 0;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		struct drm_device *dev;
> + *		int ret;
> + *
> + *		// ... Initialize the device...
> + *		dev = devm_drm_dev_alloc();
> + *		...
> + *
> + *		// ... and acquire ownership of the framebuffer.
> + *		ret = acquire_framebuffers(dev, pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * The generic driver is now subject to forced removal by other drivers. This
> + * is when the detach function in struct &drm_aperture_funcs comes into play.
> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> + * for the registered framebuffer range, the DRM core calls struct
> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> + * may not access the device's registers, framebuffer memory, ROM, etc after
> + * detach returned. If the driver supports hotplugging, detach can be treated
> + * like an unplug event.
> + *
> + * .. code-block:: c
> + *
> + *	static void detach_from_device(struct drm_device *dev,
> + *				       resource_size_t base,
> + *				       resource_size_t size)
> + *	{
> + *		// Signal unplug
> + *		drm_dev_unplug(dev);
> + *
> + *		// Maybe do other clean-up operations
> + *		...
> + *	}
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = detach_from_device,
> + *	};
> + */
> +
> +/**
> + * struct drm_aperture - Represents a DRM framebuffer aperture
> + *
> + * This structure has no public fields.
> + */
> +struct drm_aperture {
> +	struct drm_device *dev;
> +	resource_size_t base;
> +	resource_size_t size;
> +
> +	const struct drm_aperture_funcs *funcs;
> +
> +	struct list_head lh;
> +};
> +
> +static LIST_HEAD(drm_apertures);
> +
> +static DEFINE_MUTEX(drm_apertures_lock);
> +
> +static bool overlap(resource_size_t base1, resource_size_t end1,
> +		    resource_size_t base2, resource_size_t end2)
> +{
> +	return (base1 < end2) && (end1 > base2);
> +}
> +
> +static void devm_aperture_acquire_release(void *data)
> +{
> +	struct drm_aperture *ap = data;
> +	bool detached = !ap->dev;
> +
> +	if (!detached)

Uh this needs a comment that if ap->dev is NULL then we're called from
drm_aperture_detach_drivers() and hence the lock is already held.

> +		mutex_lock(&drm_apertures_lock);

and an

	else
		locdep_assert_held(&drm_apertures_lock);

here to check that. I was scratching my head first quite a bit how you'd
solve the deadlock, this is a neat solution (much simpler than anything I
came up with in my head). But needs comments.

> +
> +	list_del(&ap->lh);
> +
> +	if (!detached)
> +		mutex_unlock(&drm_apertures_lock);
> +}
> +
> +/**
> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> + * @dev:	the DRM device to own the framebuffer memory
> + * @base:	the framebuffer's byte offset in physical memory
> + * @size:	the framebuffer size in bytes
> + * @funcs:	callback functions
> + *
> + * Installs the given device as the new owner. The function fails if the
> + * framebuffer range, or parts of it, is currently owned by another driver.
> + * To evict current owners, callers should use
> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> + * function. Acquired apertures are released automatically if the underlying
> + * device goes away.
> + *
> + * Returns:
> + * An instance of struct &drm_aperture on success, or a pointer-encoded
> + * errno value otherwise.
> + */
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs)
> +{
> +	size_t end = base + size;
> +	struct list_head *pos;
> +	struct drm_aperture *ap;
> +	int ret;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each(pos, &drm_apertures) {
> +		ap = container_of(pos, struct drm_aperture, lh);
> +		if (overlap(base, end, ap->base, ap->base + ap->size))
> +			return ERR_PTR(-EBUSY);
> +	}
> +
> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> +	if (!ap)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ap->dev = dev;
> +	ap->base = base;
> +	ap->size = size;
> +	ap->funcs = funcs;
> +	INIT_LIST_HEAD(&ap->lh);
> +
> +	list_add(&ap->lh, &drm_apertures);
> +
> +	mutex_unlock(&drm_apertures_lock);
> +
> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return ap;
> +}
> +EXPORT_SYMBOL(devm_aperture_acquire);
> +
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +	resource_size_t end = base + size;
> +	struct list_head *pos, *n;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each_safe(pos, n, &drm_apertures) {
> +		struct drm_aperture *ap =
> +			container_of(pos, struct drm_aperture, lh);
> +		struct drm_device *dev = ap->dev;
> +
> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> +			continue;
> +
> +		ap->dev = NULL; /* detach from device */
> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> +			continue;
> +		ap->funcs->detach(dev, ap->base, ap->size);
> +	}
> +
> +	mutex_unlock(&drm_apertures_lock);
> +}
> +EXPORT_SYMBOL(drm_aperture_detach_drivers);

Is this just exported because of the inline functions in the headers? Imo
better to make them proper functions (they're big after your patch&not
perf critical, so not good candidates for inlining anyway).

> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> index 13766efe9517..696cec75ef78 100644
> --- a/include/drm/drm_aperture.h
> +++ b/include/drm/drm_aperture.h
> @@ -4,8 +4,30 @@
>  #define _DRM_APERTURE_H_
>  
>  #include <linux/fb.h>
> +#include <linux/pci.h>
>  #include <linux/vgaarb.h>
>  
> +struct drm_aperture;
> +struct drm_device;
> +
> +struct drm_aperture_funcs {
> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> +};
> +
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs);
> +
> +#if defined(CONFIG_DRM_APERTURE)
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> +#else
> +static inline void
> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +}
> +#endif
> +
>  /**
>   * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>   * @a: memory range, users of which are to be removed
> @@ -20,6 +42,11 @@ static inline int
>  drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>  					      const char *name, bool primary)
>  {
> +	int i;
> +
> +	for (i = 0; i < a->count; ++i)
> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> +
>  #if IS_REACHABLE(CONFIG_FB)
>  	return remove_conflicting_framebuffers(a, name, primary);
>  #else
> @@ -43,7 +70,16 @@ static inline int
>  drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>  						  const char *name)
>  {
> -	int ret = 0;
> +	resource_size_t base, size;
> +	int bar, ret = 0;
> +
> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> +			continue;
> +		base = pci_resource_start(pdev, bar);
> +		size = pci_resource_len(pdev, bar);
> +		drm_aperture_detach_drivers(base, size);
> +	}
>  
>  	/*
>  	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-08  9:48     ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie, daniel,
	sam

On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> Platform devices might operate on firmware framebuffers, such as VESA or
> EFI. Before a native driver for the graphics hardware can take over the
> device, it has to remove any platform driver that operates on the firmware
> framebuffer. Aperture helpers provide the infrastructure for platform
> drivers to acquire firmware framebuffers, and for native drivers to remove
> them later on.
> 
> It works similar to the related fbdev mechanism. During initialization, the
> platform driver acquires the firmware framebuffer's I/O memory and provides
> a callback to be removed. The native driver later uses this information to
> remove any platform driver for it's framebuffer I/O memory.
> 
> The aperture removal code is integrated into the existing code for removing
> conflicting framebuffers, so native drivers use it automatically.
> 
> v2:
> 	* rename plaform helpers to aperture helpers
> 	* tie to device lifetime with devm_ functions
> 	* removed unsued remove() callback
> 	* rename kickout to detach
> 	* make struct drm_aperture private
> 	* rebase onto existing drm_aperture.h header file
> 	* use MIT license only for simplicity
> 	* documentation
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Bunch of bikesheds for your considerations below, but overall lgtm.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Cheers, Daniel

> ---
>  Documentation/gpu/drm-internals.rst |   6 +
>  drivers/gpu/drm/Kconfig             |   7 +
>  drivers/gpu/drm/Makefile            |   1 +
>  drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>  include/drm/drm_aperture.h          |  38 +++-
>  5 files changed, 338 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 4c7642d2ca34..06af044c882f 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>  Managing Ownership of the Framebuffer Aperture
>  ----------------------------------------------
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :doc: overview
> +
>  .. kernel-doc:: include/drm/drm_aperture.h
>     :internal:
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :export:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 1461652921be..b9d3fb91d22d 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -221,6 +221,13 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_APERTURE
> +	bool
> +	depends on DRM
> +	help
> +	  Controls ownership of graphics apertures. Required to
> +	  synchronize with firmware-based drivers.

Uh I'm not a big fan of Kconfig and .ko modules for every little helper
code. Imo just stuff this into the drm kms helpers and done. Or stuff it
into drm core code, I think either is a good case for this. Everything is
its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
get funny ideas about using these internals ...

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 5eb5bf7c16e3..c9ecb02df0f3 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_PCI) += drm_pci.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o
>  obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> new file mode 100644
> index 000000000000..4b02b5fed0a1
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_aperture.c
> @@ -0,0 +1,287 @@
> +// SPDX-License-Identifier: MIT
> +
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_aperture.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * DOC: overview
> + *
> + * A graphics device might be supported by different drivers, but only one
> + * driver can be active at any given time. Many systems load a generic
> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> + * During later boot stages, they replace the generic driver with a dedicated,
> + * hardware-specific driver. To take over the device the dedicated driver
> + * first has to remove the generic driver. DRM aperture functions manage
> + * ownership of DRM framebuffer memory and hand-over between drivers.
> + *
> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> + * at the top of their probe function. The function removes any generic
> + * driver that is currently associated with the given framebuffer memory.
> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> + * example given below.
> + *
> + * .. code-block:: c
> + *
> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> + *	{
> + *		struct apertures_struct *ap;
> + *		bool primary = false;
> + *		int ret;
> + *
> + *		ap = alloc_apertures(1);
> + *		if (!ap)
> + *			return -ENOMEM;
> + *
> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> + *
> + *	#ifdef CONFIG_X86
> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> + *	#endif
> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> + *		kfree(ap);
> + *
> + *		return ret;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = remove_conflicting_framebuffers(pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> + * and let it detect the framebuffer apertures automatically.

Maybe just me, but to avoid overstretching the attention spawn of doc
readers I'd avoid this example here. And maybe make the recommendation
stronger, e.g. "PCI device drivers can avoid open-coding
remove_conflicting_framebuffers() by calling
drm_fb_helper_remove_conflicting_pci_framebuffers()."

> + *
> + * .. code-block:: c
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * Drivers that are susceptible to being removed be other drivers, such as
> + * generic EFI or VESA drivers, have to register themselves as owners of their
> + * given framebuffer memory. Ownership of the framebuffer memory is achived
> + * by calling devm_aperture_acquire(). On success, the driver is the owner
> + * of the framebuffer range. The function fails if the framebuffer is already
> + * by another driver. See below for an example.
> + *
> + * .. code-block:: c
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = ...

Is there really value in allowing/forcing drivers to set up their own
detach ops? You already make this specific to struct drm_device, an
implementation that just calls drm_dev_unplug feels like the right thing
to do?

Or maybe we should tie this more into the struct device mode and force an
unload that way? That way devm cleanup would work as one expects, and
avoid the need for anything specific (hopefully) in this detach callback.

Just feels a bit like we're reinventing half of the driver model here,
badly.

> + *	};
> + *
> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> + *	{
> + *		resource_size_t start, len;
> + *		struct drm_aperture *ap;
> + *
> + *		base = pci_resource_start(pdev, 0);
> + *		size = pci_resource_len(pdev, 0);
> + *
> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> + *		if (IS_ERR(ap))
> + *			return PTR_ERR(ap);
> + *
> + *		return 0;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		struct drm_device *dev;
> + *		int ret;
> + *
> + *		// ... Initialize the device...
> + *		dev = devm_drm_dev_alloc();
> + *		...
> + *
> + *		// ... and acquire ownership of the framebuffer.
> + *		ret = acquire_framebuffers(dev, pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * The generic driver is now subject to forced removal by other drivers. This
> + * is when the detach function in struct &drm_aperture_funcs comes into play.
> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> + * for the registered framebuffer range, the DRM core calls struct
> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> + * may not access the device's registers, framebuffer memory, ROM, etc after
> + * detach returned. If the driver supports hotplugging, detach can be treated
> + * like an unplug event.
> + *
> + * .. code-block:: c
> + *
> + *	static void detach_from_device(struct drm_device *dev,
> + *				       resource_size_t base,
> + *				       resource_size_t size)
> + *	{
> + *		// Signal unplug
> + *		drm_dev_unplug(dev);
> + *
> + *		// Maybe do other clean-up operations
> + *		...
> + *	}
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = detach_from_device,
> + *	};
> + */
> +
> +/**
> + * struct drm_aperture - Represents a DRM framebuffer aperture
> + *
> + * This structure has no public fields.
> + */
> +struct drm_aperture {
> +	struct drm_device *dev;
> +	resource_size_t base;
> +	resource_size_t size;
> +
> +	const struct drm_aperture_funcs *funcs;
> +
> +	struct list_head lh;
> +};
> +
> +static LIST_HEAD(drm_apertures);
> +
> +static DEFINE_MUTEX(drm_apertures_lock);
> +
> +static bool overlap(resource_size_t base1, resource_size_t end1,
> +		    resource_size_t base2, resource_size_t end2)
> +{
> +	return (base1 < end2) && (end1 > base2);
> +}
> +
> +static void devm_aperture_acquire_release(void *data)
> +{
> +	struct drm_aperture *ap = data;
> +	bool detached = !ap->dev;
> +
> +	if (!detached)

Uh this needs a comment that if ap->dev is NULL then we're called from
drm_aperture_detach_drivers() and hence the lock is already held.

> +		mutex_lock(&drm_apertures_lock);

and an

	else
		locdep_assert_held(&drm_apertures_lock);

here to check that. I was scratching my head first quite a bit how you'd
solve the deadlock, this is a neat solution (much simpler than anything I
came up with in my head). But needs comments.

> +
> +	list_del(&ap->lh);
> +
> +	if (!detached)
> +		mutex_unlock(&drm_apertures_lock);
> +}
> +
> +/**
> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> + * @dev:	the DRM device to own the framebuffer memory
> + * @base:	the framebuffer's byte offset in physical memory
> + * @size:	the framebuffer size in bytes
> + * @funcs:	callback functions
> + *
> + * Installs the given device as the new owner. The function fails if the
> + * framebuffer range, or parts of it, is currently owned by another driver.
> + * To evict current owners, callers should use
> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> + * function. Acquired apertures are released automatically if the underlying
> + * device goes away.
> + *
> + * Returns:
> + * An instance of struct &drm_aperture on success, or a pointer-encoded
> + * errno value otherwise.
> + */
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs)
> +{
> +	size_t end = base + size;
> +	struct list_head *pos;
> +	struct drm_aperture *ap;
> +	int ret;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each(pos, &drm_apertures) {
> +		ap = container_of(pos, struct drm_aperture, lh);
> +		if (overlap(base, end, ap->base, ap->base + ap->size))
> +			return ERR_PTR(-EBUSY);
> +	}
> +
> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> +	if (!ap)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ap->dev = dev;
> +	ap->base = base;
> +	ap->size = size;
> +	ap->funcs = funcs;
> +	INIT_LIST_HEAD(&ap->lh);
> +
> +	list_add(&ap->lh, &drm_apertures);
> +
> +	mutex_unlock(&drm_apertures_lock);
> +
> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return ap;
> +}
> +EXPORT_SYMBOL(devm_aperture_acquire);
> +
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +	resource_size_t end = base + size;
> +	struct list_head *pos, *n;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each_safe(pos, n, &drm_apertures) {
> +		struct drm_aperture *ap =
> +			container_of(pos, struct drm_aperture, lh);
> +		struct drm_device *dev = ap->dev;
> +
> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> +			continue;
> +
> +		ap->dev = NULL; /* detach from device */
> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> +			continue;
> +		ap->funcs->detach(dev, ap->base, ap->size);
> +	}
> +
> +	mutex_unlock(&drm_apertures_lock);
> +}
> +EXPORT_SYMBOL(drm_aperture_detach_drivers);

Is this just exported because of the inline functions in the headers? Imo
better to make them proper functions (they're big after your patch&not
perf critical, so not good candidates for inlining anyway).

> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> index 13766efe9517..696cec75ef78 100644
> --- a/include/drm/drm_aperture.h
> +++ b/include/drm/drm_aperture.h
> @@ -4,8 +4,30 @@
>  #define _DRM_APERTURE_H_
>  
>  #include <linux/fb.h>
> +#include <linux/pci.h>
>  #include <linux/vgaarb.h>
>  
> +struct drm_aperture;
> +struct drm_device;
> +
> +struct drm_aperture_funcs {
> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> +};
> +
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs);
> +
> +#if defined(CONFIG_DRM_APERTURE)
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> +#else
> +static inline void
> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +}
> +#endif
> +
>  /**
>   * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>   * @a: memory range, users of which are to be removed
> @@ -20,6 +42,11 @@ static inline int
>  drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>  					      const char *name, bool primary)
>  {
> +	int i;
> +
> +	for (i = 0; i < a->count; ++i)
> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> +
>  #if IS_REACHABLE(CONFIG_FB)
>  	return remove_conflicting_framebuffers(a, name, primary);
>  #else
> @@ -43,7 +70,16 @@ static inline int
>  drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>  						  const char *name)
>  {
> -	int ret = 0;
> +	resource_size_t base, size;
> +	int bar, ret = 0;
> +
> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> +			continue;
> +		base = pci_resource_start(pdev, bar);
> +		size = pci_resource_len(pdev, bar);
> +		drm_aperture_detach_drivers(base, size);
> +	}
>  
>  	/*
>  	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-08  9:48     ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam

On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> Platform devices might operate on firmware framebuffers, such as VESA or
> EFI. Before a native driver for the graphics hardware can take over the
> device, it has to remove any platform driver that operates on the firmware
> framebuffer. Aperture helpers provide the infrastructure for platform
> drivers to acquire firmware framebuffers, and for native drivers to remove
> them later on.
> 
> It works similar to the related fbdev mechanism. During initialization, the
> platform driver acquires the firmware framebuffer's I/O memory and provides
> a callback to be removed. The native driver later uses this information to
> remove any platform driver for it's framebuffer I/O memory.
> 
> The aperture removal code is integrated into the existing code for removing
> conflicting framebuffers, so native drivers use it automatically.
> 
> v2:
> 	* rename plaform helpers to aperture helpers
> 	* tie to device lifetime with devm_ functions
> 	* removed unsued remove() callback
> 	* rename kickout to detach
> 	* make struct drm_aperture private
> 	* rebase onto existing drm_aperture.h header file
> 	* use MIT license only for simplicity
> 	* documentation
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

Bunch of bikesheds for your considerations below, but overall lgtm.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Cheers, Daniel

> ---
>  Documentation/gpu/drm-internals.rst |   6 +
>  drivers/gpu/drm/Kconfig             |   7 +
>  drivers/gpu/drm/Makefile            |   1 +
>  drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>  include/drm/drm_aperture.h          |  38 +++-
>  5 files changed, 338 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_aperture.c
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 4c7642d2ca34..06af044c882f 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>  Managing Ownership of the Framebuffer Aperture
>  ----------------------------------------------
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :doc: overview
> +
>  .. kernel-doc:: include/drm/drm_aperture.h
>     :internal:
>  
> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> +   :export:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 1461652921be..b9d3fb91d22d 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -221,6 +221,13 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_APERTURE
> +	bool
> +	depends on DRM
> +	help
> +	  Controls ownership of graphics apertures. Required to
> +	  synchronize with firmware-based drivers.

Uh I'm not a big fan of Kconfig and .ko modules for every little helper
code. Imo just stuff this into the drm kms helpers and done. Or stuff it
into drm core code, I think either is a good case for this. Everything is
its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
get funny ideas about using these internals ...

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 5eb5bf7c16e3..c9ecb02df0f3 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_PCI) += drm_pci.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o
>  obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> new file mode 100644
> index 000000000000..4b02b5fed0a1
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_aperture.c
> @@ -0,0 +1,287 @@
> +// SPDX-License-Identifier: MIT
> +
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_aperture.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * DOC: overview
> + *
> + * A graphics device might be supported by different drivers, but only one
> + * driver can be active at any given time. Many systems load a generic
> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> + * During later boot stages, they replace the generic driver with a dedicated,
> + * hardware-specific driver. To take over the device the dedicated driver
> + * first has to remove the generic driver. DRM aperture functions manage
> + * ownership of DRM framebuffer memory and hand-over between drivers.
> + *
> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> + * at the top of their probe function. The function removes any generic
> + * driver that is currently associated with the given framebuffer memory.
> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> + * example given below.
> + *
> + * .. code-block:: c
> + *
> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> + *	{
> + *		struct apertures_struct *ap;
> + *		bool primary = false;
> + *		int ret;
> + *
> + *		ap = alloc_apertures(1);
> + *		if (!ap)
> + *			return -ENOMEM;
> + *
> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> + *
> + *	#ifdef CONFIG_X86
> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> + *	#endif
> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> + *		kfree(ap);
> + *
> + *		return ret;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = remove_conflicting_framebuffers(pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> + * and let it detect the framebuffer apertures automatically.

Maybe just me, but to avoid overstretching the attention spawn of doc
readers I'd avoid this example here. And maybe make the recommendation
stronger, e.g. "PCI device drivers can avoid open-coding
remove_conflicting_framebuffers() by calling
drm_fb_helper_remove_conflicting_pci_framebuffers()."

> + *
> + * .. code-block:: c
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		int ret;
> + *
> + *		// Remove any generic drivers...
> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> + *		if (ret)
> + *			return ret;
> + *
> + *		// ... and initialize the hardware.
> + *		...
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * Drivers that are susceptible to being removed be other drivers, such as
> + * generic EFI or VESA drivers, have to register themselves as owners of their
> + * given framebuffer memory. Ownership of the framebuffer memory is achived
> + * by calling devm_aperture_acquire(). On success, the driver is the owner
> + * of the framebuffer range. The function fails if the framebuffer is already
> + * by another driver. See below for an example.
> + *
> + * .. code-block:: c
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = ...

Is there really value in allowing/forcing drivers to set up their own
detach ops? You already make this specific to struct drm_device, an
implementation that just calls drm_dev_unplug feels like the right thing
to do?

Or maybe we should tie this more into the struct device mode and force an
unload that way? That way devm cleanup would work as one expects, and
avoid the need for anything specific (hopefully) in this detach callback.

Just feels a bit like we're reinventing half of the driver model here,
badly.

> + *	};
> + *
> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> + *	{
> + *		resource_size_t start, len;
> + *		struct drm_aperture *ap;
> + *
> + *		base = pci_resource_start(pdev, 0);
> + *		size = pci_resource_len(pdev, 0);
> + *
> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> + *		if (IS_ERR(ap))
> + *			return PTR_ERR(ap);
> + *
> + *		return 0;
> + *	}
> + *
> + *	static int probe(struct pci_dev *pdev)
> + *	{
> + *		struct drm_device *dev;
> + *		int ret;
> + *
> + *		// ... Initialize the device...
> + *		dev = devm_drm_dev_alloc();
> + *		...
> + *
> + *		// ... and acquire ownership of the framebuffer.
> + *		ret = acquire_framebuffers(dev, pdev);
> + *		if (ret)
> + *			return ret;
> + *
> + *		drm_dev_register();
> + *
> + *		return 0;
> + *	}
> + *
> + * The generic driver is now subject to forced removal by other drivers. This
> + * is when the detach function in struct &drm_aperture_funcs comes into play.
> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> + * for the registered framebuffer range, the DRM core calls struct
> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> + * may not access the device's registers, framebuffer memory, ROM, etc after
> + * detach returned. If the driver supports hotplugging, detach can be treated
> + * like an unplug event.
> + *
> + * .. code-block:: c
> + *
> + *	static void detach_from_device(struct drm_device *dev,
> + *				       resource_size_t base,
> + *				       resource_size_t size)
> + *	{
> + *		// Signal unplug
> + *		drm_dev_unplug(dev);
> + *
> + *		// Maybe do other clean-up operations
> + *		...
> + *	}
> + *
> + *	static struct drm_aperture_funcs ap_funcs = {
> + *		.detach = detach_from_device,
> + *	};
> + */
> +
> +/**
> + * struct drm_aperture - Represents a DRM framebuffer aperture
> + *
> + * This structure has no public fields.
> + */
> +struct drm_aperture {
> +	struct drm_device *dev;
> +	resource_size_t base;
> +	resource_size_t size;
> +
> +	const struct drm_aperture_funcs *funcs;
> +
> +	struct list_head lh;
> +};
> +
> +static LIST_HEAD(drm_apertures);
> +
> +static DEFINE_MUTEX(drm_apertures_lock);
> +
> +static bool overlap(resource_size_t base1, resource_size_t end1,
> +		    resource_size_t base2, resource_size_t end2)
> +{
> +	return (base1 < end2) && (end1 > base2);
> +}
> +
> +static void devm_aperture_acquire_release(void *data)
> +{
> +	struct drm_aperture *ap = data;
> +	bool detached = !ap->dev;
> +
> +	if (!detached)

Uh this needs a comment that if ap->dev is NULL then we're called from
drm_aperture_detach_drivers() and hence the lock is already held.

> +		mutex_lock(&drm_apertures_lock);

and an

	else
		locdep_assert_held(&drm_apertures_lock);

here to check that. I was scratching my head first quite a bit how you'd
solve the deadlock, this is a neat solution (much simpler than anything I
came up with in my head). But needs comments.

> +
> +	list_del(&ap->lh);
> +
> +	if (!detached)
> +		mutex_unlock(&drm_apertures_lock);
> +}
> +
> +/**
> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> + * @dev:	the DRM device to own the framebuffer memory
> + * @base:	the framebuffer's byte offset in physical memory
> + * @size:	the framebuffer size in bytes
> + * @funcs:	callback functions
> + *
> + * Installs the given device as the new owner. The function fails if the
> + * framebuffer range, or parts of it, is currently owned by another driver.
> + * To evict current owners, callers should use
> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> + * function. Acquired apertures are released automatically if the underlying
> + * device goes away.
> + *
> + * Returns:
> + * An instance of struct &drm_aperture on success, or a pointer-encoded
> + * errno value otherwise.
> + */
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs)
> +{
> +	size_t end = base + size;
> +	struct list_head *pos;
> +	struct drm_aperture *ap;
> +	int ret;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each(pos, &drm_apertures) {
> +		ap = container_of(pos, struct drm_aperture, lh);
> +		if (overlap(base, end, ap->base, ap->base + ap->size))
> +			return ERR_PTR(-EBUSY);
> +	}
> +
> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> +	if (!ap)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ap->dev = dev;
> +	ap->base = base;
> +	ap->size = size;
> +	ap->funcs = funcs;
> +	INIT_LIST_HEAD(&ap->lh);
> +
> +	list_add(&ap->lh, &drm_apertures);
> +
> +	mutex_unlock(&drm_apertures_lock);
> +
> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return ap;
> +}
> +EXPORT_SYMBOL(devm_aperture_acquire);
> +
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +	resource_size_t end = base + size;
> +	struct list_head *pos, *n;
> +
> +	mutex_lock(&drm_apertures_lock);
> +
> +	list_for_each_safe(pos, n, &drm_apertures) {
> +		struct drm_aperture *ap =
> +			container_of(pos, struct drm_aperture, lh);
> +		struct drm_device *dev = ap->dev;
> +
> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> +			continue;
> +
> +		ap->dev = NULL; /* detach from device */
> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> +			continue;
> +		ap->funcs->detach(dev, ap->base, ap->size);
> +	}
> +
> +	mutex_unlock(&drm_apertures_lock);
> +}
> +EXPORT_SYMBOL(drm_aperture_detach_drivers);

Is this just exported because of the inline functions in the headers? Imo
better to make them proper functions (they're big after your patch&not
perf critical, so not good candidates for inlining anyway).

> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> index 13766efe9517..696cec75ef78 100644
> --- a/include/drm/drm_aperture.h
> +++ b/include/drm/drm_aperture.h
> @@ -4,8 +4,30 @@
>  #define _DRM_APERTURE_H_
>  
>  #include <linux/fb.h>
> +#include <linux/pci.h>
>  #include <linux/vgaarb.h>
>  
> +struct drm_aperture;
> +struct drm_device;
> +
> +struct drm_aperture_funcs {
> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> +};
> +
> +struct drm_aperture *
> +devm_aperture_acquire(struct drm_device *dev,
> +		      resource_size_t base, resource_size_t size,
> +		      const struct drm_aperture_funcs *funcs);
> +
> +#if defined(CONFIG_DRM_APERTURE)
> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> +#else
> +static inline void
> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> +{
> +}
> +#endif
> +
>  /**
>   * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>   * @a: memory range, users of which are to be removed
> @@ -20,6 +42,11 @@ static inline int
>  drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>  					      const char *name, bool primary)
>  {
> +	int i;
> +
> +	for (i = 0; i < a->count; ++i)
> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> +
>  #if IS_REACHABLE(CONFIG_FB)
>  	return remove_conflicting_framebuffers(a, name, primary);
>  #else
> @@ -43,7 +70,16 @@ static inline int
>  drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>  						  const char *name)
>  {
> -	int ret = 0;
> +	resource_size_t base, size;
> +	int bar, ret = 0;
> +
> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> +			continue;
> +		base = pci_resource_start(pdev, bar);
> +		size = pci_resource_len(pdev, bar);
> +		drm_aperture_detach_drivers(base, size);
> +	}
>  
>  	/*
>  	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  2021-03-18 10:29   ` Thomas Zimmermann
  (?)
@ 2021-04-08  9:50     ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:50 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: daniel, airlied, maarten.lankhorst, mripard, kraxel, corbet,
	lgirdwood, broonie, sam, robh, emil.l.velikov, geert+renesas,
	hdegoede, bluescreen_avenger, dri-devel, linux-doc,
	virtualization

On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
> Fbdev's helpers for handling conflicting framebuffers are related to
> framebuffer apertures, not console emulation. Therefore move them into a
> drm_aperture.h, which will contain the interfaces for the new aperture
> helpers.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> ---
>  Documentation/gpu/drm-internals.rst |  6 +++
>  include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>  include/drm/drm_fb_helper.h         | 56 ++-------------------------
>  3 files changed, 69 insertions(+), 53 deletions(-)
>  create mode 100644 include/drm/drm_aperture.h
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 12272b168580..4c7642d2ca34 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>  kernel log at initialization time and passes it to userspace through the
>  DRM_IOCTL_VERSION ioctl.
>  
> +Managing Ownership of the Framebuffer Aperture
> +----------------------------------------------
> +
> +.. kernel-doc:: include/drm/drm_aperture.h
> +   :internal:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> new file mode 100644
> index 000000000000..13766efe9517
> --- /dev/null
> +++ b/include/drm/drm_aperture.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef _DRM_APERTURE_H_
> +#define _DRM_APERTURE_H_
> +
> +#include <linux/fb.h>
> +#include <linux/vgaarb.h>
> +
> +/**
> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers

Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
consistency. Also make them real functions, they're quite big and will
grow more in the next patch.

I'm also not super happy about the naming here but oh well.

Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> + * @a: memory range, users of which are to be removed
> + * @name: requesting driver name
> + * @primary: also kick vga16fb if present
> + *
> + * This function removes framebuffer devices (initialized by firmware/bootloader)
> + * which use memory range described by @a. If @a is NULL all such devices are
> + * removed.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> +					      const char *name, bool primary)
> +{
> +#if IS_REACHABLE(CONFIG_FB)
> +	return remove_conflicting_framebuffers(a, name, primary);
> +#else
> +	return 0;
> +#endif
> +}
> +
> +/**
> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
> + *                                                     framebuffers for PCI devices
> + * @pdev: PCI device
> + * @name: requesting driver name
> + *
> + * This function removes framebuffer devices (eg. initialized by firmware)
> + * using memory range configured for any of @pdev's memory bars.
> + *
> + * The function assumes that PCI device with shadowed ROM drives a primary
> + * display and so kicks out vga16fb.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> +						  const char *name)
> +{
> +	int ret = 0;
> +
> +	/*
> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> +	 * otherwise the vga fbdev driver falls over.
> +	 */
> +#if IS_REACHABLE(CONFIG_FB)
> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
> +#endif
> +	if (ret == 0)
> +		ret = vga_remove_vgacon(pdev);
> +	return ret;
> +}
> +
> +#endif
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 3b273f9ca39a..d06a3942fddb 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -30,13 +30,13 @@
>  #ifndef DRM_FB_HELPER_H
>  #define DRM_FB_HELPER_H
>  
> -struct drm_fb_helper;
> -
> +#include <drm/drm_aperture.h>
>  #include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_device.h>
>  #include <linux/kgdb.h>
> -#include <linux/vgaarb.h>
> +
> +struct drm_fb_helper;
>  
>  enum mode_set_atomic {
>  	LEAVE_ATOMIC_MODE_SET,
> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>  
>  #endif
>  
> -/**
> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> - * @a: memory range, users of which are to be removed
> - * @name: requesting driver name
> - * @primary: also kick vga16fb if present
> - *
> - * This function removes framebuffer devices (initialized by firmware/bootloader)
> - * which use memory range described by @a. If @a is NULL all such devices are
> - * removed.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> -					      const char *name, bool primary)
> -{
> -#if IS_REACHABLE(CONFIG_FB)
> -	return remove_conflicting_framebuffers(a, name, primary);
> -#else
> -	return 0;
> -#endif
> -}
> -
> -/**
> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
> - * @pdev: PCI device
> - * @name: requesting driver name
> - *
> - * This function removes framebuffer devices (eg. initialized by firmware)
> - * using memory range configured for any of @pdev's memory bars.
> - *
> - * The function assumes that PCI device with shadowed ROM drives a primary
> - * display and so kicks out vga16fb.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> -						  const char *name)
> -{
> -	int ret = 0;
> -
> -	/*
> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -	 * otherwise the vga fbdev driver falls over.
> -	 */
> -#if IS_REACHABLE(CONFIG_FB)
> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
> -#endif
> -	if (ret == 0)
> -		ret = vga_remove_vgacon(pdev);
> -	return ret;
> -}
> -
>  #endif
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-04-08  9:50     ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:50 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie, daniel,
	sam

On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
> Fbdev's helpers for handling conflicting framebuffers are related to
> framebuffer apertures, not console emulation. Therefore move them into a
> drm_aperture.h, which will contain the interfaces for the new aperture
> helpers.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> ---
>  Documentation/gpu/drm-internals.rst |  6 +++
>  include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>  include/drm/drm_fb_helper.h         | 56 ++-------------------------
>  3 files changed, 69 insertions(+), 53 deletions(-)
>  create mode 100644 include/drm/drm_aperture.h
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 12272b168580..4c7642d2ca34 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>  kernel log at initialization time and passes it to userspace through the
>  DRM_IOCTL_VERSION ioctl.
>  
> +Managing Ownership of the Framebuffer Aperture
> +----------------------------------------------
> +
> +.. kernel-doc:: include/drm/drm_aperture.h
> +   :internal:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> new file mode 100644
> index 000000000000..13766efe9517
> --- /dev/null
> +++ b/include/drm/drm_aperture.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef _DRM_APERTURE_H_
> +#define _DRM_APERTURE_H_
> +
> +#include <linux/fb.h>
> +#include <linux/vgaarb.h>
> +
> +/**
> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers

Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
consistency. Also make them real functions, they're quite big and will
grow more in the next patch.

I'm also not super happy about the naming here but oh well.

Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> + * @a: memory range, users of which are to be removed
> + * @name: requesting driver name
> + * @primary: also kick vga16fb if present
> + *
> + * This function removes framebuffer devices (initialized by firmware/bootloader)
> + * which use memory range described by @a. If @a is NULL all such devices are
> + * removed.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> +					      const char *name, bool primary)
> +{
> +#if IS_REACHABLE(CONFIG_FB)
> +	return remove_conflicting_framebuffers(a, name, primary);
> +#else
> +	return 0;
> +#endif
> +}
> +
> +/**
> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
> + *                                                     framebuffers for PCI devices
> + * @pdev: PCI device
> + * @name: requesting driver name
> + *
> + * This function removes framebuffer devices (eg. initialized by firmware)
> + * using memory range configured for any of @pdev's memory bars.
> + *
> + * The function assumes that PCI device with shadowed ROM drives a primary
> + * display and so kicks out vga16fb.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> +						  const char *name)
> +{
> +	int ret = 0;
> +
> +	/*
> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> +	 * otherwise the vga fbdev driver falls over.
> +	 */
> +#if IS_REACHABLE(CONFIG_FB)
> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
> +#endif
> +	if (ret == 0)
> +		ret = vga_remove_vgacon(pdev);
> +	return ret;
> +}
> +
> +#endif
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 3b273f9ca39a..d06a3942fddb 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -30,13 +30,13 @@
>  #ifndef DRM_FB_HELPER_H
>  #define DRM_FB_HELPER_H
>  
> -struct drm_fb_helper;
> -
> +#include <drm/drm_aperture.h>
>  #include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_device.h>
>  #include <linux/kgdb.h>
> -#include <linux/vgaarb.h>
> +
> +struct drm_fb_helper;
>  
>  enum mode_set_atomic {
>  	LEAVE_ATOMIC_MODE_SET,
> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>  
>  #endif
>  
> -/**
> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> - * @a: memory range, users of which are to be removed
> - * @name: requesting driver name
> - * @primary: also kick vga16fb if present
> - *
> - * This function removes framebuffer devices (initialized by firmware/bootloader)
> - * which use memory range described by @a. If @a is NULL all such devices are
> - * removed.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> -					      const char *name, bool primary)
> -{
> -#if IS_REACHABLE(CONFIG_FB)
> -	return remove_conflicting_framebuffers(a, name, primary);
> -#else
> -	return 0;
> -#endif
> -}
> -
> -/**
> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
> - * @pdev: PCI device
> - * @name: requesting driver name
> - *
> - * This function removes framebuffer devices (eg. initialized by firmware)
> - * using memory range configured for any of @pdev's memory bars.
> - *
> - * The function assumes that PCI device with shadowed ROM drives a primary
> - * display and so kicks out vga16fb.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> -						  const char *name)
> -{
> -	int ret = 0;
> -
> -	/*
> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -	 * otherwise the vga fbdev driver falls over.
> -	 */
> -#if IS_REACHABLE(CONFIG_FB)
> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
> -#endif
> -	if (ret == 0)
> -		ret = vga_remove_vgacon(pdev);
> -	return ret;
> -}
> -
>  #endif
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-04-08  9:50     ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08  9:50 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam

On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
> Fbdev's helpers for handling conflicting framebuffers are related to
> framebuffer apertures, not console emulation. Therefore move them into a
> drm_aperture.h, which will contain the interfaces for the new aperture
> helpers.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> ---
>  Documentation/gpu/drm-internals.rst |  6 +++
>  include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>  include/drm/drm_fb_helper.h         | 56 ++-------------------------
>  3 files changed, 69 insertions(+), 53 deletions(-)
>  create mode 100644 include/drm/drm_aperture.h
> 
> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> index 12272b168580..4c7642d2ca34 100644
> --- a/Documentation/gpu/drm-internals.rst
> +++ b/Documentation/gpu/drm-internals.rst
> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>  kernel log at initialization time and passes it to userspace through the
>  DRM_IOCTL_VERSION ioctl.
>  
> +Managing Ownership of the Framebuffer Aperture
> +----------------------------------------------
> +
> +.. kernel-doc:: include/drm/drm_aperture.h
> +   :internal:
> +
>  Device Instance and Driver Handling
>  -----------------------------------
>  
> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> new file mode 100644
> index 000000000000..13766efe9517
> --- /dev/null
> +++ b/include/drm/drm_aperture.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef _DRM_APERTURE_H_
> +#define _DRM_APERTURE_H_
> +
> +#include <linux/fb.h>
> +#include <linux/vgaarb.h>
> +
> +/**
> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers

Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
consistency. Also make them real functions, they're quite big and will
grow more in the next patch.

I'm also not super happy about the naming here but oh well.

Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> + * @a: memory range, users of which are to be removed
> + * @name: requesting driver name
> + * @primary: also kick vga16fb if present
> + *
> + * This function removes framebuffer devices (initialized by firmware/bootloader)
> + * which use memory range described by @a. If @a is NULL all such devices are
> + * removed.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> +					      const char *name, bool primary)
> +{
> +#if IS_REACHABLE(CONFIG_FB)
> +	return remove_conflicting_framebuffers(a, name, primary);
> +#else
> +	return 0;
> +#endif
> +}
> +
> +/**
> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
> + *                                                     framebuffers for PCI devices
> + * @pdev: PCI device
> + * @name: requesting driver name
> + *
> + * This function removes framebuffer devices (eg. initialized by firmware)
> + * using memory range configured for any of @pdev's memory bars.
> + *
> + * The function assumes that PCI device with shadowed ROM drives a primary
> + * display and so kicks out vga16fb.
> + */
> +static inline int
> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> +						  const char *name)
> +{
> +	int ret = 0;
> +
> +	/*
> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> +	 * otherwise the vga fbdev driver falls over.
> +	 */
> +#if IS_REACHABLE(CONFIG_FB)
> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
> +#endif
> +	if (ret == 0)
> +		ret = vga_remove_vgacon(pdev);
> +	return ret;
> +}
> +
> +#endif
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 3b273f9ca39a..d06a3942fddb 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -30,13 +30,13 @@
>  #ifndef DRM_FB_HELPER_H
>  #define DRM_FB_HELPER_H
>  
> -struct drm_fb_helper;
> -
> +#include <drm/drm_aperture.h>
>  #include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_device.h>
>  #include <linux/kgdb.h>
> -#include <linux/vgaarb.h>
> +
> +struct drm_fb_helper;
>  
>  enum mode_set_atomic {
>  	LEAVE_ATOMIC_MODE_SET,
> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>  
>  #endif
>  
> -/**
> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> - * @a: memory range, users of which are to be removed
> - * @name: requesting driver name
> - * @primary: also kick vga16fb if present
> - *
> - * This function removes framebuffer devices (initialized by firmware/bootloader)
> - * which use memory range described by @a. If @a is NULL all such devices are
> - * removed.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> -					      const char *name, bool primary)
> -{
> -#if IS_REACHABLE(CONFIG_FB)
> -	return remove_conflicting_framebuffers(a, name, primary);
> -#else
> -	return 0;
> -#endif
> -}
> -
> -/**
> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
> - * @pdev: PCI device
> - * @name: requesting driver name
> - *
> - * This function removes framebuffer devices (eg. initialized by firmware)
> - * using memory range configured for any of @pdev's memory bars.
> - *
> - * The function assumes that PCI device with shadowed ROM drives a primary
> - * display and so kicks out vga16fb.
> - */
> -static inline int
> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> -						  const char *name)
> -{
> -	int ret = 0;
> -
> -	/*
> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> -	 * otherwise the vga fbdev driver falls over.
> -	 */
> -#if IS_REACHABLE(CONFIG_FB)
> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
> -#endif
> -	if (ret == 0)
> -		ret = vga_remove_vgacon(pdev);
> -	return ret;
> -}
> -
>  #endif
> -- 
> 2.30.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
  2021-03-30  8:34           ` Hans de Goede
  (?)
@ 2021-04-08 10:14             ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08 10:14 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Thomas Zimmermann, daniel, airlied, maarten.lankhorst, mripard,
	kraxel, corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, bluescreen_avenger, virtualization, dri-devel,
	linux-doc

On Tue, Mar 30, 2021 at 10:34:12AM +0200, Hans de Goede wrote:
> Hi,
> 
> On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 29.03.21 um 16:50 schrieb Hans de Goede:
> >> Hi,
> >>
> >> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> >>> Hi
> >>>
> >>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
> >>>> Hi,
> >>>>
> >>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> >>>>> This patchset adds support for simple-framebuffer platform devices and
> >>>>> a handover mechanism for native drivers to take-over control of the
> >>>>> hardware.
> >>>>>
> >>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
> >>>>> device. The kernel's boot code creates such devices for firmware-provided
> >>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> >>>>> loader sets up the framebuffers. Description via device tree is also an
> >>>>> option.
> >>>>>
> >>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
> >>>>> purpose is to provide graphical output during the early phases of the boot
> >>>>> process, before the native DRM drivers are available. Native drivers are
> >>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
> >>>>> serve as interim solution on graphics hardware without native DRM driver.
> >>>>>
> >>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> >>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
> >>>>> the drivers do not provide DRM interfaces for modern userspace.
> >>>>>
> >>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> >>>>>
> >>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> >>>>> framebuffer's I/O-memory range and provides a callback function to be
> >>>>> removed by a native driver. The native driver will remove simpledrm before
> >>>>> taking over the hardware. The removal is integrated into existing helpers,
> >>>>> so drivers use it automatically.
> >>>>>
> >>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> >>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> >>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> >>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> >>>>> regulators. It's based on the simplefb drivers, but has been modified for
> >>>>> DRM.
> >>>>
> >>>> Thank you for your work on this, this is very interesting.
> >>>>
> >>>>> I've also been working on fastboot support (i.e., flicker-free booting).
> >>>>> This requires state-readout from simpledrm via generic interfaces, as
> >>>>> outlined in [1]. I do have some prototype code, but it will take a while
> >>>>> to get this ready. Simpledrm will then support it.
> >>>>>
> >>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> >>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
> >>>>> manual configuration of the device. Xorgs current modesetting driver does
> >>>>> not work with both, platform and PCI device, for the same physical
> >>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> >>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> >>>>> I expect the problem to become a non-issue soon. Additional testing has
> >>>>> been reported at [2].
> >>>>>
> >>>>> One cosmetical issue is that simpledrm's device file is card0 and the
> >>>>> native driver's device file is card1. After simpledrm has been kicked out,
> >>>>> only card1 is left. This does not seem to be a practical problem however.
> >>>>>
> >>>>> TODO/IDEAS:
> >>>>>
> >>>>>      * provide deferred takeover
> >>>>
> >>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
> >>>> handled in the fbcon code. Current flickerfree boot works like this
> >>>> (assuming a single LCD panel in a laptop):
> >>>>
> >>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> >>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
> >>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> >>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
> >>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
> >>>>      the console and leaves the dummy-console driver in place (unless there have already
> >>>>      been kernel messages logged, which there shouldn't because loglevel=3)
> >>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
> >>>>      panel which it would set, they match, nothing happens. i915 takes ownership
> >>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
> >>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
> >>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
> >>>>      console driver in place as console driver.
> >>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
> >>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
> >>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
> >>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
> >>>>      sees no changes, other then the spinner appearing
> >>>>      (note the active VT is now in graphical mode)
> >>>> 5. From here on not flickering is a userspace problem
> >>>>
> >>>> AFAICT this should work fine with simplekms too, unless it clears the screen
> >>>> to black when it binds.
> >>>
> >>> I forgot to add the code that clears the screen, but that's the case here.
> >>>
> >>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> >>
> >> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> >> an in kernel drm-client or userspace seems wrong, this is certainly different from
> >> what the i915 driver does. The way I see it either a drm client provides a new
> >> framebuffer in which case you copy that over the old contents, effectively clearing
> >> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> >> case it is the clients responsibility to clear it itself first.
> >>
> >> IOW I believe that simpledrm should not clear the screen itself at all.
> > 
> > I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.
> 
> Sounds good, thanks.

To clarify: Atomic assumes that the sw state always matches hw state, even
at boot-up. Most drivers use drm_mode_config_reset to achieve that, which
forces everything to off. But that breaks flicker-free boot.

To avoid that i915 (and it's the only driver doing so) has fairly
elaborate state-readout code, to make sure we do faithfully preserve the
full boot-up display state. This is anything but trivial to implement.

For simpledrm it's a bit simple, since state recover boils down to reading
out the fb and putting it into the new one, since there's not even
provisions (afaiui) for simpledrm to enable/disable the output physically.

So i915 is the exception here allowing flicker-free boot, not the rule.
-Daniel

> > BTW if you have the time I'd appreciate your review of the patchset.
> 
> Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.
> 
> Regards,
> 
> Hans
> 
> 
> 
> 
> 
> >>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> >>>
> >>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> >>>
> >>> Best regards
> >>> Thomas
> >>>
> >>>>
> >>>> An addition to the above sequence, if at any time either the kernel or userspace
> >>>> prints a message to the console; and at that time a fbdev is registered then fbcon
> >>>> will takeover as the console driver from the dummy driver and it will start drawing
> >>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> >>>> where printend while no fbdev was registered, then fbcon will takeover the console
> >>>> as soon as a fbdev gets registered.
> >>>>
> >>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
> >>>> mean when you are talking about "provide deferred takeover" for simplekms?
> >>>>
> >>>> Regards,
> >>>>
> >>>> Hans
> >>>>
> >>>>
> >>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> >>>> will delay using the fbdev until the VT is switched back to text mode.
> >>>>
> >>>>
> >>>> p.s.
> >>>>
> >>>> This has the interesting side effect then when logging into a desktop GUI session:
> >>>> kernel -> plymouth -> gdm -> GNOME user session
> >>>>
> >>>> There never is any output to the text-console and fbcon never takes-over, so on
> >>>> many Laptops running say Fedora workstation the fbcon code is actually unused
> >>>> until the user manually switches to another virtual-console to log in in
> >>>> text-mode:
> >>>>
> >>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> >>>> [    0.258904] Console: colour dummy device 80x25
> >>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> >>>> [    1.274768] fbcon: Deferring console take-over
> >>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> >>>> [    2.540896] fbcon: Deferring console take-over
> >>>> [hans@x1 ~]$ uptime
> >>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> >>>>
> >>>> Look mom no fbcon
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>      * provide bootsplash DRM client
> >>>>>      * make simplekms usable with ARM-EFI fbs
> >>>>>
> >>>>> v2:
> >>>>>      * rename to simpledrm, aperture helpers
> >>>>>      * reorganized patches
> >>>>>      * use hotplug helpers for removal (Daniel)
> >>>>>      * added DT match tables (Rob)
> >>>>>      * use shadow-plane helpers
> >>>>>      * lots of minor cleanups
> >>>>>
> >>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> >>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> >>>>>
> >>>>> Thomas Zimmermann (10):
> >>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
> >>>>>     drm/format-helper: Add blitter functions
> >>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
> >>>>>     drm/aperture: Add infrastructure for aperture ownership
> >>>>>     drm: Add simpledrm driver
> >>>>>     drm/simpledrm: Add fbdev emulation
> >>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
> >>>>>     drm/simpledrm: Acquire clocks from DT device node
> >>>>>     drm/simpledrm: Acquire regulators from DT device node
> >>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
> >>>>>
> >>>>>    Documentation/gpu/drm-internals.rst    |  12 +
> >>>>>    MAINTAINERS                            |   7 +
> >>>>>    drivers/gpu/drm/Kconfig                |   7 +
> >>>>>    drivers/gpu/drm/Makefile               |   1 +
> >>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
> >>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
> >>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
> >>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
> >>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
> >>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
> >>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
> >>>>>    include/drm/drm_aperture.h             |  96 +++
> >>>>>    include/drm/drm_fb_helper.h            |  56 +-
> >>>>>    include/drm/drm_format_helper.h        |  10 +-
> >>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
> >>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
> >>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
> >>>>>    create mode 100644 include/drm/drm_aperture.h
> >>>>>
> >>>>> -- 
> >>>>> 2.30.1
> >>>>>
> >>>>
> >>>
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>
> > 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-04-08 10:14             ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08 10:14 UTC (permalink / raw)
  To: Hans de Goede
  Cc: robh, bluescreen_avenger, Thomas Zimmermann, geert+renesas,
	corbet, airlied, emil.l.velikov, dri-devel, linux-doc,
	maarten.lankhorst, lgirdwood, mripard, virtualization, broonie,
	daniel, sam

On Tue, Mar 30, 2021 at 10:34:12AM +0200, Hans de Goede wrote:
> Hi,
> 
> On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 29.03.21 um 16:50 schrieb Hans de Goede:
> >> Hi,
> >>
> >> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> >>> Hi
> >>>
> >>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
> >>>> Hi,
> >>>>
> >>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> >>>>> This patchset adds support for simple-framebuffer platform devices and
> >>>>> a handover mechanism for native drivers to take-over control of the
> >>>>> hardware.
> >>>>>
> >>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
> >>>>> device. The kernel's boot code creates such devices for firmware-provided
> >>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> >>>>> loader sets up the framebuffers. Description via device tree is also an
> >>>>> option.
> >>>>>
> >>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
> >>>>> purpose is to provide graphical output during the early phases of the boot
> >>>>> process, before the native DRM drivers are available. Native drivers are
> >>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
> >>>>> serve as interim solution on graphics hardware without native DRM driver.
> >>>>>
> >>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> >>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
> >>>>> the drivers do not provide DRM interfaces for modern userspace.
> >>>>>
> >>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> >>>>>
> >>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> >>>>> framebuffer's I/O-memory range and provides a callback function to be
> >>>>> removed by a native driver. The native driver will remove simpledrm before
> >>>>> taking over the hardware. The removal is integrated into existing helpers,
> >>>>> so drivers use it automatically.
> >>>>>
> >>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> >>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> >>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> >>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> >>>>> regulators. It's based on the simplefb drivers, but has been modified for
> >>>>> DRM.
> >>>>
> >>>> Thank you for your work on this, this is very interesting.
> >>>>
> >>>>> I've also been working on fastboot support (i.e., flicker-free booting).
> >>>>> This requires state-readout from simpledrm via generic interfaces, as
> >>>>> outlined in [1]. I do have some prototype code, but it will take a while
> >>>>> to get this ready. Simpledrm will then support it.
> >>>>>
> >>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> >>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
> >>>>> manual configuration of the device. Xorgs current modesetting driver does
> >>>>> not work with both, platform and PCI device, for the same physical
> >>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> >>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> >>>>> I expect the problem to become a non-issue soon. Additional testing has
> >>>>> been reported at [2].
> >>>>>
> >>>>> One cosmetical issue is that simpledrm's device file is card0 and the
> >>>>> native driver's device file is card1. After simpledrm has been kicked out,
> >>>>> only card1 is left. This does not seem to be a practical problem however.
> >>>>>
> >>>>> TODO/IDEAS:
> >>>>>
> >>>>>      * provide deferred takeover
> >>>>
> >>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
> >>>> handled in the fbcon code. Current flickerfree boot works like this
> >>>> (assuming a single LCD panel in a laptop):
> >>>>
> >>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> >>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
> >>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> >>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
> >>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
> >>>>      the console and leaves the dummy-console driver in place (unless there have already
> >>>>      been kernel messages logged, which there shouldn't because loglevel=3)
> >>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
> >>>>      panel which it would set, they match, nothing happens. i915 takes ownership
> >>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
> >>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
> >>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
> >>>>      console driver in place as console driver.
> >>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
> >>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
> >>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
> >>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
> >>>>      sees no changes, other then the spinner appearing
> >>>>      (note the active VT is now in graphical mode)
> >>>> 5. From here on not flickering is a userspace problem
> >>>>
> >>>> AFAICT this should work fine with simplekms too, unless it clears the screen
> >>>> to black when it binds.
> >>>
> >>> I forgot to add the code that clears the screen, but that's the case here.
> >>>
> >>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> >>
> >> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> >> an in kernel drm-client or userspace seems wrong, this is certainly different from
> >> what the i915 driver does. The way I see it either a drm client provides a new
> >> framebuffer in which case you copy that over the old contents, effectively clearing
> >> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> >> case it is the clients responsibility to clear it itself first.
> >>
> >> IOW I believe that simpledrm should not clear the screen itself at all.
> > 
> > I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.
> 
> Sounds good, thanks.

To clarify: Atomic assumes that the sw state always matches hw state, even
at boot-up. Most drivers use drm_mode_config_reset to achieve that, which
forces everything to off. But that breaks flicker-free boot.

To avoid that i915 (and it's the only driver doing so) has fairly
elaborate state-readout code, to make sure we do faithfully preserve the
full boot-up display state. This is anything but trivial to implement.

For simpledrm it's a bit simple, since state recover boils down to reading
out the fb and putting it into the new one, since there's not even
provisions (afaiui) for simpledrm to enable/disable the output physically.

So i915 is the exception here allowing flicker-free boot, not the rule.
-Daniel

> > BTW if you have the time I'd appreciate your review of the patchset.
> 
> Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.
> 
> Regards,
> 
> Hans
> 
> 
> 
> 
> 
> >>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> >>>
> >>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> >>>
> >>> Best regards
> >>> Thomas
> >>>
> >>>>
> >>>> An addition to the above sequence, if at any time either the kernel or userspace
> >>>> prints a message to the console; and at that time a fbdev is registered then fbcon
> >>>> will takeover as the console driver from the dummy driver and it will start drawing
> >>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> >>>> where printend while no fbdev was registered, then fbcon will takeover the console
> >>>> as soon as a fbdev gets registered.
> >>>>
> >>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
> >>>> mean when you are talking about "provide deferred takeover" for simplekms?
> >>>>
> >>>> Regards,
> >>>>
> >>>> Hans
> >>>>
> >>>>
> >>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> >>>> will delay using the fbdev until the VT is switched back to text mode.
> >>>>
> >>>>
> >>>> p.s.
> >>>>
> >>>> This has the interesting side effect then when logging into a desktop GUI session:
> >>>> kernel -> plymouth -> gdm -> GNOME user session
> >>>>
> >>>> There never is any output to the text-console and fbcon never takes-over, so on
> >>>> many Laptops running say Fedora workstation the fbcon code is actually unused
> >>>> until the user manually switches to another virtual-console to log in in
> >>>> text-mode:
> >>>>
> >>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> >>>> [    0.258904] Console: colour dummy device 80x25
> >>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> >>>> [    1.274768] fbcon: Deferring console take-over
> >>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> >>>> [    2.540896] fbcon: Deferring console take-over
> >>>> [hans@x1 ~]$ uptime
> >>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> >>>>
> >>>> Look mom no fbcon
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>      * provide bootsplash DRM client
> >>>>>      * make simplekms usable with ARM-EFI fbs
> >>>>>
> >>>>> v2:
> >>>>>      * rename to simpledrm, aperture helpers
> >>>>>      * reorganized patches
> >>>>>      * use hotplug helpers for removal (Daniel)
> >>>>>      * added DT match tables (Rob)
> >>>>>      * use shadow-plane helpers
> >>>>>      * lots of minor cleanups
> >>>>>
> >>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> >>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> >>>>>
> >>>>> Thomas Zimmermann (10):
> >>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
> >>>>>     drm/format-helper: Add blitter functions
> >>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
> >>>>>     drm/aperture: Add infrastructure for aperture ownership
> >>>>>     drm: Add simpledrm driver
> >>>>>     drm/simpledrm: Add fbdev emulation
> >>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
> >>>>>     drm/simpledrm: Acquire clocks from DT device node
> >>>>>     drm/simpledrm: Acquire regulators from DT device node
> >>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
> >>>>>
> >>>>>    Documentation/gpu/drm-internals.rst    |  12 +
> >>>>>    MAINTAINERS                            |   7 +
> >>>>>    drivers/gpu/drm/Kconfig                |   7 +
> >>>>>    drivers/gpu/drm/Makefile               |   1 +
> >>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
> >>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
> >>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
> >>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
> >>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
> >>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
> >>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
> >>>>>    include/drm/drm_aperture.h             |  96 +++
> >>>>>    include/drm/drm_fb_helper.h            |  56 +-
> >>>>>    include/drm/drm_format_helper.h        |  10 +-
> >>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
> >>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
> >>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
> >>>>>    create mode 100644 include/drm/drm_aperture.h
> >>>>>
> >>>>> -- 
> >>>>> 2.30.1
> >>>>>
> >>>>
> >>>
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>
> > 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs
@ 2021-04-08 10:14             ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-08 10:14 UTC (permalink / raw)
  To: Hans de Goede
  Cc: bluescreen_avenger, Thomas Zimmermann, geert+renesas, corbet,
	airlied, emil.l.velikov, dri-devel, linux-doc, lgirdwood,
	virtualization, broonie, kraxel, sam

On Tue, Mar 30, 2021 at 10:34:12AM +0200, Hans de Goede wrote:
> Hi,
> 
> On 3/30/21 9:09 AM, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 29.03.21 um 16:50 schrieb Hans de Goede:
> >> Hi,
> >>
> >> On 3/29/21 2:31 PM, Thomas Zimmermann wrote:
> >>> Hi
> >>>
> >>> Am 25.03.21 um 12:29 schrieb Hans de Goede:
> >>>> Hi,
> >>>>
> >>>> On 3/18/21 11:29 AM, Thomas Zimmermann wrote:
> >>>>> This patchset adds support for simple-framebuffer platform devices and
> >>>>> a handover mechanism for native drivers to take-over control of the
> >>>>> hardware.
> >>>>>
> >>>>> The new driver, called simpledrm, binds to a simple-frambuffer platform
> >>>>> device. The kernel's boot code creates such devices for firmware-provided
> >>>>> framebuffers, such as EFI-GOP or VESA. Typically the BIOS, UEFI or boot
> >>>>> loader sets up the framebuffers. Description via device tree is also an
> >>>>> option.
> >>>>>
> >>>>> Simpledrm is small enough to be linked into the kernel. The driver's main
> >>>>> purpose is to provide graphical output during the early phases of the boot
> >>>>> process, before the native DRM drivers are available. Native drivers are
> >>>>> typically loaded from an initrd ram disk. Occationally simpledrm can also
> >>>>> serve as interim solution on graphics hardware without native DRM driver.
> >>>>>
> >>>>> So far distributions rely on fbdev drivers, such as efifb, vesafb or
> >>>>> simplefb, for early-boot graphical output. However fbdev is deprecated and
> >>>>> the drivers do not provide DRM interfaces for modern userspace.
> >>>>>
> >>>>> Patches 1 and 2 prepare the DRM format helpers for simpledrm.
> >>>>>
> >>>>> Patches 3 and 4 add a hand-over mechanism. Simpledrm acquires it's
> >>>>> framebuffer's I/O-memory range and provides a callback function to be
> >>>>> removed by a native driver. The native driver will remove simpledrm before
> >>>>> taking over the hardware. The removal is integrated into existing helpers,
> >>>>> so drivers use it automatically.
> >>>>>
> >>>>> Patches 5 to 10 add the simpledrm driver. It's build on simple DRM helpers
> >>>>> and SHMEM. It supports 16-bit, 24-bit and 32-bit RGB framebuffers. During
> >>>>> pageflips, SHMEM buffers are copied into the framebuffer memory, similar
> >>>>> to cirrus or mgag200. The code in patches 8 and 9 handles clocks and
> >>>>> regulators. It's based on the simplefb drivers, but has been modified for
> >>>>> DRM.
> >>>>
> >>>> Thank you for your work on this, this is very interesting.
> >>>>
> >>>>> I've also been working on fastboot support (i.e., flicker-free booting).
> >>>>> This requires state-readout from simpledrm via generic interfaces, as
> >>>>> outlined in [1]. I do have some prototype code, but it will take a while
> >>>>> to get this ready. Simpledrm will then support it.
> >>>>>
> >>>>> I've tested simpledrm with x86 EFI and VESA framebuffers, which both work
> >>>>> reliably. The fbdev console and Weston work automatically. Xorg requires
> >>>>> manual configuration of the device. Xorgs current modesetting driver does
> >>>>> not work with both, platform and PCI device, for the same physical
> >>>>> hardware. Once configured, X11 works. I looked into X11, but couldn't see
> >>>>> an easy way of fixing the problem. With the push towards Wayland+Xwayland
> >>>>> I expect the problem to become a non-issue soon. Additional testing has
> >>>>> been reported at [2].
> >>>>>
> >>>>> One cosmetical issue is that simpledrm's device file is card0 and the
> >>>>> native driver's device file is card1. After simpledrm has been kicked out,
> >>>>> only card1 is left. This does not seem to be a practical problem however.
> >>>>>
> >>>>> TODO/IDEAS:
> >>>>>
> >>>>>      * provide deferred takeover
> >>>>
> >>>> I'm not sure what you mean with this ?  Currently deferred-takeover is
> >>>> handled in the fbcon code. Current flickerfree boot works like this
> >>>> (assuming a single LCD panel in a laptop):
> >>>>
> >>>> 1. EFI/GOP sets up the framebuffer, draws a vendor logo
> >>>> 2. The bootloader runs in silent mode and does not touch anything gfx related
> >>>> 3. kernel boots, with a loglevel of 3 so only CRIT/EMERG messages are shown
> >>>> 2. efifb loads; and tells fbcon that a framebuffer is now available for it to "bind"
> >>>>      to. Since CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y fbcon defers taking over
> >>>>      the console and leaves the dummy-console driver in place (unless there have already
> >>>>      been kernel messages logged, which there shouldn't because loglevel=3)
> >>>> 3. i915 loads, reads out the hw state compares this to the preferred-mode for the
> >>>>      panel which it would set, they match, nothing happens. i915 takes ownership
> >>>>      of the scanout-buffer set up by the GOP, but leaves it in place.
> >>>>      i915 also removes the efifb /dev/fb0 and installs its own /dev/fb0 fbdev compat
> >>>>      device, fbcon is notified of this, but is still deferred and leaves the dummy
> >>>>      console driver in place as console driver.
> >>>> 4. Plymouth loads, allocates a new scan-out buffer at the panel's preferred resolution,
> >>>>      plymouth reads the vendor-logo through the BGRT ACPI interface and fills the
> >>>>      scanout-buffer with the vendor-logo + a spinner. Then plymouth installs the new
> >>>>      scanout-buffer on the crtc, this is done atomically during vsync, so the user
> >>>>      sees no changes, other then the spinner appearing
> >>>>      (note the active VT is now in graphical mode)
> >>>> 5. From here on not flickering is a userspace problem
> >>>>
> >>>> AFAICT this should work fine with simplekms too, unless it clears the screen
> >>>> to black when it binds.
> >>>
> >>> I forgot to add the code that clears the screen, but that's the case here.
> >>>
> >>> Instead of a plane-disable operation, simpledrm can at best clear the screen. This would happen during the initial mode-config reset IIRC.
> >>
> >> Hmm, clearing the screen without any (atomic) modesets being initiated by either
> >> an in kernel drm-client or userspace seems wrong, this is certainly different from
> >> what the i915 driver does. The way I see it either a drm client provides a new
> >> framebuffer in which case you copy that over the old contents, effectively clearing
> >> it. Or a drm-client gets a handle and draws to the current fb directly, in which
> >> case it is the clients responsibility to clear it itself first.
> >>
> >> IOW I believe that simpledrm should not clear the screen itself at all.
> > 
> > I do as well. And when I boot with simpledrm + native driver it's flicker-free from what I can tell. But drm_mode_config_reset() is supposed to reset HW and software state. There could be some corner case where we'd have to clear the screen. For now, it should be fine.
> 
> Sounds good, thanks.

To clarify: Atomic assumes that the sw state always matches hw state, even
at boot-up. Most drivers use drm_mode_config_reset to achieve that, which
forces everything to off. But that breaks flicker-free boot.

To avoid that i915 (and it's the only driver doing so) has fairly
elaborate state-readout code, to make sure we do faithfully preserve the
full boot-up display state. This is anything but trivial to implement.

For simpledrm it's a bit simple, since state recover boils down to reading
out the fb and putting it into the new one, since there's not even
provisions (afaiui) for simpledrm to enable/disable the output physically.

So i915 is the exception here allowing flicker-free boot, not the rule.
-Daniel

> > BTW if you have the time I'd appreciate your review of the patchset.
> 
> Sorry, but I'm burried under a whole pile of other work. So although I would like to help it is better to say no.
> 
> Regards,
> 
> Hans
> 
> 
> 
> 
> 
> >>> But we need to keep the display content stored in a framebuffer, so read-out helpers are required. There are more users of these read-out helpers. Adding them at some point probably makes sense.
> >>>
> >>> Other drivers might also want to read the initial config from simpledrm via read-out helpers. I think only i915 currently supports something like that ATM.
> >>>
> >>> Best regards
> >>> Thomas
> >>>
> >>>>
> >>>> An addition to the above sequence, if at any time either the kernel or userspace
> >>>> prints a message to the console; and at that time a fbdev is registered then fbcon
> >>>> will takeover as the console driver from the dummy driver and it will start drawing
> >>>> to the registered fbdev (1), destroying the framebuffer contents. Also if any messages
> >>>> where printend while no fbdev was registered, then fbcon will takeover the console
> >>>> as soon as a fbdev gets registered.
> >>>>
> >>>> So since we already have deferred-takeover in the fbcon code, I wonder what you
> >>>> mean when you are talking about "provide deferred takeover" for simplekms?
> >>>>
> >>>> Regards,
> >>>>
> >>>> Hans
> >>>>
> >>>>
> >>>> 1) Except when the VT has been switched to GFX mode when this happens, then fbcon
> >>>> will delay using the fbdev until the VT is switched back to text mode.
> >>>>
> >>>>
> >>>> p.s.
> >>>>
> >>>> This has the interesting side effect then when logging into a desktop GUI session:
> >>>> kernel -> plymouth -> gdm -> GNOME user session
> >>>>
> >>>> There never is any output to the text-console and fbcon never takes-over, so on
> >>>> many Laptops running say Fedora workstation the fbcon code is actually unused
> >>>> until the user manually switches to another virtual-console to log in in
> >>>> text-mode:
> >>>>
> >>>> [hans@x1 ~]$ dmesg | grep -E 'fbcon|Console:|Truecolor'
> >>>> [    0.258904] Console: colour dummy device 80x25
> >>>> [    1.274726] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
> >>>> [    1.274768] fbcon: Deferring console take-over
> >>>> [    2.540894] fbcon: i915drmfb (fb0) is primary device
> >>>> [    2.540896] fbcon: Deferring console take-over
> >>>> [hans@x1 ~]$ uptime
> >>>>    12:29:39 up  4:19,  1 user,  load average: 0.58, 0.75, 0.81
> >>>>
> >>>> Look mom no fbcon
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>      * provide bootsplash DRM client
> >>>>>      * make simplekms usable with ARM-EFI fbs
> >>>>>
> >>>>> v2:
> >>>>>      * rename to simpledrm, aperture helpers
> >>>>>      * reorganized patches
> >>>>>      * use hotplug helpers for removal (Daniel)
> >>>>>      * added DT match tables (Rob)
> >>>>>      * use shadow-plane helpers
> >>>>>      * lots of minor cleanups
> >>>>>
> >>>>> [1] https://lore.kernel.org/dri-devel/CAKMK7uHtqHy_oz4W7F+hmp9iqp7W5Ra8CxPvJ=9BwmvfU-O0gg@mail.gmail.com/
> >>>>> [2] https://lore.kernel.org/dri-devel/1761762.3HQLrFs1K7@nerdopolis/
> >>>>>
> >>>>> Thomas Zimmermann (10):
> >>>>>     drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip()
> >>>>>     drm/format-helper: Add blitter functions
> >>>>>     drm/aperture: Move fbdev conflict helpers into drm_aperture.h
> >>>>>     drm/aperture: Add infrastructure for aperture ownership
> >>>>>     drm: Add simpledrm driver
> >>>>>     drm/simpledrm: Add fbdev emulation
> >>>>>     drm/simpledrm: Initialize framebuffer data from device-tree node
> >>>>>     drm/simpledrm: Acquire clocks from DT device node
> >>>>>     drm/simpledrm: Acquire regulators from DT device node
> >>>>>     drm/simpledrm: Acquire memory aperture for framebuffer
> >>>>>
> >>>>>    Documentation/gpu/drm-internals.rst    |  12 +
> >>>>>    MAINTAINERS                            |   7 +
> >>>>>    drivers/gpu/drm/Kconfig                |   7 +
> >>>>>    drivers/gpu/drm/Makefile               |   1 +
> >>>>>    drivers/gpu/drm/drm_aperture.c         | 287 ++++++++
> >>>>>    drivers/gpu/drm/drm_format_helper.c    |  96 ++-
> >>>>>    drivers/gpu/drm/mgag200/mgag200_mode.c |   2 +-
> >>>>>    drivers/gpu/drm/tiny/Kconfig           |  17 +
> >>>>>    drivers/gpu/drm/tiny/Makefile          |   1 +
> >>>>>    drivers/gpu/drm/tiny/cirrus.c          |   2 +-
> >>>>>    drivers/gpu/drm/tiny/simpledrm.c       | 932 +++++++++++++++++++++++++
> >>>>>    include/drm/drm_aperture.h             |  96 +++
> >>>>>    include/drm/drm_fb_helper.h            |  56 +-
> >>>>>    include/drm/drm_format_helper.h        |  10 +-
> >>>>>    14 files changed, 1466 insertions(+), 60 deletions(-)
> >>>>>    create mode 100644 drivers/gpu/drm/drm_aperture.c
> >>>>>    create mode 100644 drivers/gpu/drm/tiny/simpledrm.c
> >>>>>    create mode 100644 include/drm/drm_aperture.h
> >>>>>
> >>>>> -- 
> >>>>> 2.30.1
> >>>>>
> >>>>
> >>>
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>
> > 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-08  9:48     ` Daniel Vetter
  (?)
@ 2021-04-09  7:06       ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:06 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: airlied, maarten.lankhorst, mripard, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 10964 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."

It's a tutorial. In my expectation, everyone just copies the tutorial 
code and fills the gaps.

> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?

Is it that easy? simepldrm's detach function has code to synchronize 
with concurrent hotplug removals. If we can use drm_dev_unplug() for 
everything, I'm all for it.

Best regards
Thomas

> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  7:06       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:06 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 10964 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."

It's a tutorial. In my expectation, everyone just copies the tutorial 
code and fills the gaps.

> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?

Is it that easy? simepldrm's detach function has code to synchronize 
with concurrent hotplug removals. If we can use drm_dev_unplug() for 
everything, I'm all for it.

Best regards
Thomas

> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  7:06       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:06 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 10964 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."

It's a tutorial. In my expectation, everyone just copies the tutorial 
code and fills the gaps.

> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?

Is it that easy? simepldrm's detach function has code to synchronize 
with concurrent hotplug removals. If we can use drm_dev_unplug() for 
everything, I'm all for it.

Best regards
Thomas

> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
  2021-04-08  9:50     ` Daniel Vetter
  (?)
@ 2021-04-09  7:09       ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:09 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 7055 bytes --]

Hi

Am 08.04.21 um 11:50 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
>> Fbdev's helpers for handling conflicting framebuffers are related to
>> framebuffer apertures, not console emulation. Therefore move them into a
>> drm_aperture.h, which will contain the interfaces for the new aperture
>> helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>> ---
>>   Documentation/gpu/drm-internals.rst |  6 +++
>>   include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>>   include/drm/drm_fb_helper.h         | 56 ++-------------------------
>>   3 files changed, 69 insertions(+), 53 deletions(-)
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 12272b168580..4c7642d2ca34 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>>   kernel log at initialization time and passes it to userspace through the
>>   DRM_IOCTL_VERSION ioctl.
>>   
>> +Managing Ownership of the Framebuffer Aperture
>> +----------------------------------------------
>> +
>> +.. kernel-doc:: include/drm/drm_aperture.h
>> +   :internal:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> new file mode 100644
>> index 000000000000..13766efe9517
>> --- /dev/null
>> +++ b/include/drm/drm_aperture.h
>> @@ -0,0 +1,60 @@
>> +/* SPDX-License-Identifier: MIT */
>> +
>> +#ifndef _DRM_APERTURE_H_
>> +#define _DRM_APERTURE_H_
>> +
>> +#include <linux/fb.h>
>> +#include <linux/vgaarb.h>
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> 
> Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
> consistency. Also make them real functions, they're quite big and will
> grow more in the next patch.
> 
> I'm also not super happy about the naming here but oh well.

The original name for this was platform helpers, which was worse. So 
it's not like we're not improving. :)

I'll take this patch + some docs from patch 4 + your feedback and turn 
it into a separate patchset. It should be useful even without simpledrm.

Best regards
Thomas

> 
> Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
>> + * @a: memory range, users of which are to be removed
>> + * @name: requesting driver name
>> + * @primary: also kick vga16fb if present
>> + *
>> + * This function removes framebuffer devices (initialized by firmware/bootloader)
>> + * which use memory range described by @a. If @a is NULL all such devices are
>> + * removed.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> +					      const char *name, bool primary)
>> +{
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	return remove_conflicting_framebuffers(a, name, primary);
>> +#else
>> +	return 0;
>> +#endif
>> +}
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
>> + *                                                     framebuffers for PCI devices
>> + * @pdev: PCI device
>> + * @name: requesting driver name
>> + *
>> + * This function removes framebuffer devices (eg. initialized by firmware)
>> + * using memory range configured for any of @pdev's memory bars.
>> + *
>> + * The function assumes that PCI device with shadowed ROM drives a primary
>> + * display and so kicks out vga16fb.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> +						  const char *name)
>> +{
>> +	int ret = 0;
>> +
>> +	/*
>> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> +	 * otherwise the vga fbdev driver falls over.
>> +	 */
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> +#endif
>> +	if (ret == 0)
>> +		ret = vga_remove_vgacon(pdev);
>> +	return ret;
>> +}
>> +
>> +#endif
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 3b273f9ca39a..d06a3942fddb 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -30,13 +30,13 @@
>>   #ifndef DRM_FB_HELPER_H
>>   #define DRM_FB_HELPER_H
>>   
>> -struct drm_fb_helper;
>> -
>> +#include <drm/drm_aperture.h>
>>   #include <drm/drm_client.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_device.h>
>>   #include <linux/kgdb.h>
>> -#include <linux/vgaarb.h>
>> +
>> +struct drm_fb_helper;
>>   
>>   enum mode_set_atomic {
>>   	LEAVE_ATOMIC_MODE_SET,
>> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>>   
>>   #endif
>>   
>> -/**
>> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>> - * @a: memory range, users of which are to be removed
>> - * @name: requesting driver name
>> - * @primary: also kick vga16fb if present
>> - *
>> - * This function removes framebuffer devices (initialized by firmware/bootloader)
>> - * which use memory range described by @a. If @a is NULL all such devices are
>> - * removed.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> -					      const char *name, bool primary)
>> -{
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	return remove_conflicting_framebuffers(a, name, primary);
>> -#else
>> -	return 0;
>> -#endif
>> -}
>> -
>> -/**
>> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
>> - * @pdev: PCI device
>> - * @name: requesting driver name
>> - *
>> - * This function removes framebuffer devices (eg. initialized by firmware)
>> - * using memory range configured for any of @pdev's memory bars.
>> - *
>> - * The function assumes that PCI device with shadowed ROM drives a primary
>> - * display and so kicks out vga16fb.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> -						  const char *name)
>> -{
>> -	int ret = 0;
>> -
>> -	/*
>> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -	 * otherwise the vga fbdev driver falls over.
>> -	 */
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> -#endif
>> -	if (ret == 0)
>> -		ret = vga_remove_vgacon(pdev);
>> -	return ret;
>> -}
>> -
>>   #endif
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-04-09  7:09       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:09 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 7055 bytes --]

Hi

Am 08.04.21 um 11:50 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
>> Fbdev's helpers for handling conflicting framebuffers are related to
>> framebuffer apertures, not console emulation. Therefore move them into a
>> drm_aperture.h, which will contain the interfaces for the new aperture
>> helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>> ---
>>   Documentation/gpu/drm-internals.rst |  6 +++
>>   include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>>   include/drm/drm_fb_helper.h         | 56 ++-------------------------
>>   3 files changed, 69 insertions(+), 53 deletions(-)
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 12272b168580..4c7642d2ca34 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>>   kernel log at initialization time and passes it to userspace through the
>>   DRM_IOCTL_VERSION ioctl.
>>   
>> +Managing Ownership of the Framebuffer Aperture
>> +----------------------------------------------
>> +
>> +.. kernel-doc:: include/drm/drm_aperture.h
>> +   :internal:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> new file mode 100644
>> index 000000000000..13766efe9517
>> --- /dev/null
>> +++ b/include/drm/drm_aperture.h
>> @@ -0,0 +1,60 @@
>> +/* SPDX-License-Identifier: MIT */
>> +
>> +#ifndef _DRM_APERTURE_H_
>> +#define _DRM_APERTURE_H_
>> +
>> +#include <linux/fb.h>
>> +#include <linux/vgaarb.h>
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> 
> Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
> consistency. Also make them real functions, they're quite big and will
> grow more in the next patch.
> 
> I'm also not super happy about the naming here but oh well.

The original name for this was platform helpers, which was worse. So 
it's not like we're not improving. :)

I'll take this patch + some docs from patch 4 + your feedback and turn 
it into a separate patchset. It should be useful even without simpledrm.

Best regards
Thomas

> 
> Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
>> + * @a: memory range, users of which are to be removed
>> + * @name: requesting driver name
>> + * @primary: also kick vga16fb if present
>> + *
>> + * This function removes framebuffer devices (initialized by firmware/bootloader)
>> + * which use memory range described by @a. If @a is NULL all such devices are
>> + * removed.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> +					      const char *name, bool primary)
>> +{
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	return remove_conflicting_framebuffers(a, name, primary);
>> +#else
>> +	return 0;
>> +#endif
>> +}
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
>> + *                                                     framebuffers for PCI devices
>> + * @pdev: PCI device
>> + * @name: requesting driver name
>> + *
>> + * This function removes framebuffer devices (eg. initialized by firmware)
>> + * using memory range configured for any of @pdev's memory bars.
>> + *
>> + * The function assumes that PCI device with shadowed ROM drives a primary
>> + * display and so kicks out vga16fb.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> +						  const char *name)
>> +{
>> +	int ret = 0;
>> +
>> +	/*
>> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> +	 * otherwise the vga fbdev driver falls over.
>> +	 */
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> +#endif
>> +	if (ret == 0)
>> +		ret = vga_remove_vgacon(pdev);
>> +	return ret;
>> +}
>> +
>> +#endif
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 3b273f9ca39a..d06a3942fddb 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -30,13 +30,13 @@
>>   #ifndef DRM_FB_HELPER_H
>>   #define DRM_FB_HELPER_H
>>   
>> -struct drm_fb_helper;
>> -
>> +#include <drm/drm_aperture.h>
>>   #include <drm/drm_client.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_device.h>
>>   #include <linux/kgdb.h>
>> -#include <linux/vgaarb.h>
>> +
>> +struct drm_fb_helper;
>>   
>>   enum mode_set_atomic {
>>   	LEAVE_ATOMIC_MODE_SET,
>> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>>   
>>   #endif
>>   
>> -/**
>> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>> - * @a: memory range, users of which are to be removed
>> - * @name: requesting driver name
>> - * @primary: also kick vga16fb if present
>> - *
>> - * This function removes framebuffer devices (initialized by firmware/bootloader)
>> - * which use memory range described by @a. If @a is NULL all such devices are
>> - * removed.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> -					      const char *name, bool primary)
>> -{
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	return remove_conflicting_framebuffers(a, name, primary);
>> -#else
>> -	return 0;
>> -#endif
>> -}
>> -
>> -/**
>> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
>> - * @pdev: PCI device
>> - * @name: requesting driver name
>> - *
>> - * This function removes framebuffer devices (eg. initialized by firmware)
>> - * using memory range configured for any of @pdev's memory bars.
>> - *
>> - * The function assumes that PCI device with shadowed ROM drives a primary
>> - * display and so kicks out vga16fb.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> -						  const char *name)
>> -{
>> -	int ret = 0;
>> -
>> -	/*
>> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -	 * otherwise the vga fbdev driver falls over.
>> -	 */
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> -#endif
>> -	if (ret == 0)
>> -		ret = vga_remove_vgacon(pdev);
>> -	return ret;
>> -}
>> -
>>   #endif
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h
@ 2021-04-09  7:09       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:09 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 7055 bytes --]

Hi

Am 08.04.21 um 11:50 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:14AM +0100, Thomas Zimmermann wrote:
>> Fbdev's helpers for handling conflicting framebuffers are related to
>> framebuffer apertures, not console emulation. Therefore move them into a
>> drm_aperture.h, which will contain the interfaces for the new aperture
>> helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>> ---
>>   Documentation/gpu/drm-internals.rst |  6 +++
>>   include/drm/drm_aperture.h          | 60 +++++++++++++++++++++++++++++
>>   include/drm/drm_fb_helper.h         | 56 ++-------------------------
>>   3 files changed, 69 insertions(+), 53 deletions(-)
>>   create mode 100644 include/drm/drm_aperture.h
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 12272b168580..4c7642d2ca34 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
>>   kernel log at initialization time and passes it to userspace through the
>>   DRM_IOCTL_VERSION ioctl.
>>   
>> +Managing Ownership of the Framebuffer Aperture
>> +----------------------------------------------
>> +
>> +.. kernel-doc:: include/drm/drm_aperture.h
>> +   :internal:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> new file mode 100644
>> index 000000000000..13766efe9517
>> --- /dev/null
>> +++ b/include/drm/drm_aperture.h
>> @@ -0,0 +1,60 @@
>> +/* SPDX-License-Identifier: MIT */
>> +
>> +#ifndef _DRM_APERTURE_H_
>> +#define _DRM_APERTURE_H_
>> +
>> +#include <linux/fb.h>
>> +#include <linux/vgaarb.h>
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> 
> Annoying bikeshed, but I'd give them drm_aperture_ prefixes, for ocd
> consistency. Also make them real functions, they're quite big and will
> grow more in the next patch.
> 
> I'm also not super happy about the naming here but oh well.

The original name for this was platform helpers, which was worse. So 
it's not like we're not improving. :)

I'll take this patch + some docs from patch 4 + your feedback and turn 
it into a separate patchset. It should be useful even without simpledrm.

Best regards
Thomas

> 
> Either way: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
>> + * @a: memory range, users of which are to be removed
>> + * @name: requesting driver name
>> + * @primary: also kick vga16fb if present
>> + *
>> + * This function removes framebuffer devices (initialized by firmware/bootloader)
>> + * which use memory range described by @a. If @a is NULL all such devices are
>> + * removed.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> +					      const char *name, bool primary)
>> +{
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	return remove_conflicting_framebuffers(a, name, primary);
>> +#else
>> +	return 0;
>> +#endif
>> +}
>> +
>> +/**
>> + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured
>> + *                                                     framebuffers for PCI devices
>> + * @pdev: PCI device
>> + * @name: requesting driver name
>> + *
>> + * This function removes framebuffer devices (eg. initialized by firmware)
>> + * using memory range configured for any of @pdev's memory bars.
>> + *
>> + * The function assumes that PCI device with shadowed ROM drives a primary
>> + * display and so kicks out vga16fb.
>> + */
>> +static inline int
>> +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> +						  const char *name)
>> +{
>> +	int ret = 0;
>> +
>> +	/*
>> +	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> +	 * otherwise the vga fbdev driver falls over.
>> +	 */
>> +#if IS_REACHABLE(CONFIG_FB)
>> +	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> +#endif
>> +	if (ret == 0)
>> +		ret = vga_remove_vgacon(pdev);
>> +	return ret;
>> +}
>> +
>> +#endif
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 3b273f9ca39a..d06a3942fddb 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -30,13 +30,13 @@
>>   #ifndef DRM_FB_HELPER_H
>>   #define DRM_FB_HELPER_H
>>   
>> -struct drm_fb_helper;
>> -
>> +#include <drm/drm_aperture.h>
>>   #include <drm/drm_client.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_device.h>
>>   #include <linux/kgdb.h>
>> -#include <linux/vgaarb.h>
>> +
>> +struct drm_fb_helper;
>>   
>>   enum mode_set_atomic {
>>   	LEAVE_ATOMIC_MODE_SET,
>> @@ -451,54 +451,4 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
>>   
>>   #endif
>>   
>> -/**
>> - * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>> - * @a: memory range, users of which are to be removed
>> - * @name: requesting driver name
>> - * @primary: also kick vga16fb if present
>> - *
>> - * This function removes framebuffer devices (initialized by firmware/bootloader)
>> - * which use memory range described by @a. If @a is NULL all such devices are
>> - * removed.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>> -					      const char *name, bool primary)
>> -{
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	return remove_conflicting_framebuffers(a, name, primary);
>> -#else
>> -	return 0;
>> -#endif
>> -}
>> -
>> -/**
>> - * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
>> - * @pdev: PCI device
>> - * @name: requesting driver name
>> - *
>> - * This function removes framebuffer devices (eg. initialized by firmware)
>> - * using memory range configured for any of @pdev's memory bars.
>> - *
>> - * The function assumes that PCI device with shadowed ROM drives a primary
>> - * display and so kicks out vga16fb.
>> - */
>> -static inline int
>> -drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>> -						  const char *name)
>> -{
>> -	int ret = 0;
>> -
>> -	/*
>> -	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -	 * otherwise the vga fbdev driver falls over.
>> -	 */
>> -#if IS_REACHABLE(CONFIG_FB)
>> -	ret = remove_conflicting_pci_framebuffers(pdev, name);
>> -#endif
>> -	if (ret == 0)
>> -		ret = vga_remove_vgacon(pdev);
>> -	return ret;
>> -}
>> -
>>   #endif
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-08  9:48     ` Daniel Vetter
  (?)
@ 2021-04-09  7:54       ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:54 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 17810 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
>> Platform devices might operate on firmware framebuffers, such as VESA or
>> EFI. Before a native driver for the graphics hardware can take over the
>> device, it has to remove any platform driver that operates on the firmware
>> framebuffer. Aperture helpers provide the infrastructure for platform
>> drivers to acquire firmware framebuffers, and for native drivers to remove
>> them later on.
>>
>> It works similar to the related fbdev mechanism. During initialization, the
>> platform driver acquires the firmware framebuffer's I/O memory and provides
>> a callback to be removed. The native driver later uses this information to
>> remove any platform driver for it's framebuffer I/O memory.
>>
>> The aperture removal code is integrated into the existing code for removing
>> conflicting framebuffers, so native drivers use it automatically.
>>
>> v2:
>> 	* rename plaform helpers to aperture helpers
>> 	* tie to device lifetime with devm_ functions
>> 	* removed unsued remove() callback
>> 	* rename kickout to detach
>> 	* make struct drm_aperture private
>> 	* rebase onto existing drm_aperture.h header file
>> 	* use MIT license only for simplicity
>> 	* documentation
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Bunch of bikesheds for your considerations below, but overall lgtm.
> 
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Cheers, Daniel
> 
>> ---
>>   Documentation/gpu/drm-internals.rst |   6 +
>>   drivers/gpu/drm/Kconfig             |   7 +
>>   drivers/gpu/drm/Makefile            |   1 +
>>   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>>   include/drm/drm_aperture.h          |  38 +++-
>>   5 files changed, 338 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 4c7642d2ca34..06af044c882f 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>>   Managing Ownership of the Framebuffer Aperture
>>   ----------------------------------------------
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :doc: overview
>> +
>>   .. kernel-doc:: include/drm/drm_aperture.h
>>      :internal:
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :export:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 1461652921be..b9d3fb91d22d 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -221,6 +221,13 @@ config DRM_SCHED
>>   	tristate
>>   	depends on DRM
>>   
>> +config DRM_APERTURE
>> +	bool
>> +	depends on DRM
>> +	help
>> +	  Controls ownership of graphics apertures. Required to
>> +	  synchronize with firmware-based drivers.
> 
> Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> into drm core code, I think either is a good case for this. Everything is
> its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> get funny ideas about using these internals ...

The code lives in the DRM core module. There's no extra ko file. But I'd 
like to keep the Kconfig option. The aperture helpers will only be 
required if there are generic drivers in the kernel and for many systems 
this is not the case.

Best regards
Thomas

> 
>> +
>>   source "drivers/gpu/drm/i2c/Kconfig"
>>   
>>   source "drivers/gpu/drm/arm/Kconfig"
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 5eb5bf7c16e3..c9ecb02df0f3 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>>   drm-$(CONFIG_PCI) += drm_pci.o
>>   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>>   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>>   
>>   drm_vram_helper-y := drm_gem_vram_helper.o
>>   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
>> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
>> new file mode 100644
>> index 000000000000..4b02b5fed0a1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_aperture.c
>> @@ -0,0 +1,287 @@
>> +// SPDX-License-Identifier: MIT
>> +
>> +#include <linux/device.h>
>> +#include <linux/list.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/types.h>
>> +
>> +#include <drm/drm_aperture.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_print.h>
>> +
>> +/**
>> + * DOC: overview
>> + *
>> + * A graphics device might be supported by different drivers, but only one
>> + * driver can be active at any given time. Many systems load a generic
>> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
>> + * During later boot stages, they replace the generic driver with a dedicated,
>> + * hardware-specific driver. To take over the device the dedicated driver
>> + * first has to remove the generic driver. DRM aperture functions manage
>> + * ownership of DRM framebuffer memory and hand-over between drivers.
>> + *
>> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
>> + * at the top of their probe function. The function removes any generic
>> + * driver that is currently associated with the given framebuffer memory.
>> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
>> + * example given below.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
>> + *	{
>> + *		struct apertures_struct *ap;
>> + *		bool primary = false;
>> + *		int ret;
>> + *
>> + *		ap = alloc_apertures(1);
>> + *		if (!ap)
>> + *			return -ENOMEM;
>> + *
>> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
>> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
>> + *
>> + *	#ifdef CONFIG_X86
>> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
>> + *	#endif
>> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
>> + *		kfree(ap);
>> + *
>> + *		return ret;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = remove_conflicting_framebuffers(pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
>> + * and let it detect the framebuffer apertures automatically.
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?
> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  7:54       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:54 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 17810 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
>> Platform devices might operate on firmware framebuffers, such as VESA or
>> EFI. Before a native driver for the graphics hardware can take over the
>> device, it has to remove any platform driver that operates on the firmware
>> framebuffer. Aperture helpers provide the infrastructure for platform
>> drivers to acquire firmware framebuffers, and for native drivers to remove
>> them later on.
>>
>> It works similar to the related fbdev mechanism. During initialization, the
>> platform driver acquires the firmware framebuffer's I/O memory and provides
>> a callback to be removed. The native driver later uses this information to
>> remove any platform driver for it's framebuffer I/O memory.
>>
>> The aperture removal code is integrated into the existing code for removing
>> conflicting framebuffers, so native drivers use it automatically.
>>
>> v2:
>> 	* rename plaform helpers to aperture helpers
>> 	* tie to device lifetime with devm_ functions
>> 	* removed unsued remove() callback
>> 	* rename kickout to detach
>> 	* make struct drm_aperture private
>> 	* rebase onto existing drm_aperture.h header file
>> 	* use MIT license only for simplicity
>> 	* documentation
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Bunch of bikesheds for your considerations below, but overall lgtm.
> 
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Cheers, Daniel
> 
>> ---
>>   Documentation/gpu/drm-internals.rst |   6 +
>>   drivers/gpu/drm/Kconfig             |   7 +
>>   drivers/gpu/drm/Makefile            |   1 +
>>   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>>   include/drm/drm_aperture.h          |  38 +++-
>>   5 files changed, 338 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 4c7642d2ca34..06af044c882f 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>>   Managing Ownership of the Framebuffer Aperture
>>   ----------------------------------------------
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :doc: overview
>> +
>>   .. kernel-doc:: include/drm/drm_aperture.h
>>      :internal:
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :export:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 1461652921be..b9d3fb91d22d 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -221,6 +221,13 @@ config DRM_SCHED
>>   	tristate
>>   	depends on DRM
>>   
>> +config DRM_APERTURE
>> +	bool
>> +	depends on DRM
>> +	help
>> +	  Controls ownership of graphics apertures. Required to
>> +	  synchronize with firmware-based drivers.
> 
> Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> into drm core code, I think either is a good case for this. Everything is
> its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> get funny ideas about using these internals ...

The code lives in the DRM core module. There's no extra ko file. But I'd 
like to keep the Kconfig option. The aperture helpers will only be 
required if there are generic drivers in the kernel and for many systems 
this is not the case.

Best regards
Thomas

> 
>> +
>>   source "drivers/gpu/drm/i2c/Kconfig"
>>   
>>   source "drivers/gpu/drm/arm/Kconfig"
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 5eb5bf7c16e3..c9ecb02df0f3 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>>   drm-$(CONFIG_PCI) += drm_pci.o
>>   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>>   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>>   
>>   drm_vram_helper-y := drm_gem_vram_helper.o
>>   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
>> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
>> new file mode 100644
>> index 000000000000..4b02b5fed0a1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_aperture.c
>> @@ -0,0 +1,287 @@
>> +// SPDX-License-Identifier: MIT
>> +
>> +#include <linux/device.h>
>> +#include <linux/list.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/types.h>
>> +
>> +#include <drm/drm_aperture.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_print.h>
>> +
>> +/**
>> + * DOC: overview
>> + *
>> + * A graphics device might be supported by different drivers, but only one
>> + * driver can be active at any given time. Many systems load a generic
>> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
>> + * During later boot stages, they replace the generic driver with a dedicated,
>> + * hardware-specific driver. To take over the device the dedicated driver
>> + * first has to remove the generic driver. DRM aperture functions manage
>> + * ownership of DRM framebuffer memory and hand-over between drivers.
>> + *
>> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
>> + * at the top of their probe function. The function removes any generic
>> + * driver that is currently associated with the given framebuffer memory.
>> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
>> + * example given below.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
>> + *	{
>> + *		struct apertures_struct *ap;
>> + *		bool primary = false;
>> + *		int ret;
>> + *
>> + *		ap = alloc_apertures(1);
>> + *		if (!ap)
>> + *			return -ENOMEM;
>> + *
>> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
>> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
>> + *
>> + *	#ifdef CONFIG_X86
>> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
>> + *	#endif
>> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
>> + *		kfree(ap);
>> + *
>> + *		return ret;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = remove_conflicting_framebuffers(pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
>> + * and let it detect the framebuffer apertures automatically.
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?
> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  7:54       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-09  7:54 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 17810 bytes --]

Hi

Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
>> Platform devices might operate on firmware framebuffers, such as VESA or
>> EFI. Before a native driver for the graphics hardware can take over the
>> device, it has to remove any platform driver that operates on the firmware
>> framebuffer. Aperture helpers provide the infrastructure for platform
>> drivers to acquire firmware framebuffers, and for native drivers to remove
>> them later on.
>>
>> It works similar to the related fbdev mechanism. During initialization, the
>> platform driver acquires the firmware framebuffer's I/O memory and provides
>> a callback to be removed. The native driver later uses this information to
>> remove any platform driver for it's framebuffer I/O memory.
>>
>> The aperture removal code is integrated into the existing code for removing
>> conflicting framebuffers, so native drivers use it automatically.
>>
>> v2:
>> 	* rename plaform helpers to aperture helpers
>> 	* tie to device lifetime with devm_ functions
>> 	* removed unsued remove() callback
>> 	* rename kickout to detach
>> 	* make struct drm_aperture private
>> 	* rebase onto existing drm_aperture.h header file
>> 	* use MIT license only for simplicity
>> 	* documentation
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Bunch of bikesheds for your considerations below, but overall lgtm.
> 
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Cheers, Daniel
> 
>> ---
>>   Documentation/gpu/drm-internals.rst |   6 +
>>   drivers/gpu/drm/Kconfig             |   7 +
>>   drivers/gpu/drm/Makefile            |   1 +
>>   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
>>   include/drm/drm_aperture.h          |  38 +++-
>>   5 files changed, 338 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/drm_aperture.c
>>
>> diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
>> index 4c7642d2ca34..06af044c882f 100644
>> --- a/Documentation/gpu/drm-internals.rst
>> +++ b/Documentation/gpu/drm-internals.rst
>> @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
>>   Managing Ownership of the Framebuffer Aperture
>>   ----------------------------------------------
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :doc: overview
>> +
>>   .. kernel-doc:: include/drm/drm_aperture.h
>>      :internal:
>>   
>> +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
>> +   :export:
>> +
>>   Device Instance and Driver Handling
>>   -----------------------------------
>>   
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 1461652921be..b9d3fb91d22d 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -221,6 +221,13 @@ config DRM_SCHED
>>   	tristate
>>   	depends on DRM
>>   
>> +config DRM_APERTURE
>> +	bool
>> +	depends on DRM
>> +	help
>> +	  Controls ownership of graphics apertures. Required to
>> +	  synchronize with firmware-based drivers.
> 
> Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> into drm core code, I think either is a good case for this. Everything is
> its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> get funny ideas about using these internals ...

The code lives in the DRM core module. There's no extra ko file. But I'd 
like to keep the Kconfig option. The aperture helpers will only be 
required if there are generic drivers in the kernel and for many systems 
this is not the case.

Best regards
Thomas

> 
>> +
>>   source "drivers/gpu/drm/i2c/Kconfig"
>>   
>>   source "drivers/gpu/drm/arm/Kconfig"
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 5eb5bf7c16e3..c9ecb02df0f3 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
>>   drm-$(CONFIG_PCI) += drm_pci.o
>>   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>>   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>> +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
>>   
>>   drm_vram_helper-y := drm_gem_vram_helper.o
>>   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
>> diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
>> new file mode 100644
>> index 000000000000..4b02b5fed0a1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_aperture.c
>> @@ -0,0 +1,287 @@
>> +// SPDX-License-Identifier: MIT
>> +
>> +#include <linux/device.h>
>> +#include <linux/list.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/types.h>
>> +
>> +#include <drm/drm_aperture.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_print.h>
>> +
>> +/**
>> + * DOC: overview
>> + *
>> + * A graphics device might be supported by different drivers, but only one
>> + * driver can be active at any given time. Many systems load a generic
>> + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
>> + * During later boot stages, they replace the generic driver with a dedicated,
>> + * hardware-specific driver. To take over the device the dedicated driver
>> + * first has to remove the generic driver. DRM aperture functions manage
>> + * ownership of DRM framebuffer memory and hand-over between drivers.
>> + *
>> + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
>> + * at the top of their probe function. The function removes any generic
>> + * driver that is currently associated with the given framebuffer memory.
>> + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
>> + * example given below.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
>> + *	{
>> + *		struct apertures_struct *ap;
>> + *		bool primary = false;
>> + *		int ret;
>> + *
>> + *		ap = alloc_apertures(1);
>> + *		if (!ap)
>> + *			return -ENOMEM;
>> + *
>> + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
>> + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
>> + *
>> + *	#ifdef CONFIG_X86
>> + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
>> + *	#endif
>> + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
>> + *		kfree(ap);
>> + *
>> + *		return ret;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = remove_conflicting_framebuffers(pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
>> + * and let it detect the framebuffer apertures automatically.
> 
> Maybe just me, but to avoid overstretching the attention spawn of doc
> readers I'd avoid this example here. And maybe make the recommendation
> stronger, e.g. "PCI device drivers can avoid open-coding
> remove_conflicting_framebuffers() by calling
> drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		int ret;
>> + *
>> + *		// Remove any generic drivers...
>> + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		// ... and initialize the hardware.
>> + *		...
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * Drivers that are susceptible to being removed be other drivers, such as
>> + * generic EFI or VESA drivers, have to register themselves as owners of their
>> + * given framebuffer memory. Ownership of the framebuffer memory is achived
>> + * by calling devm_aperture_acquire(). On success, the driver is the owner
>> + * of the framebuffer range. The function fails if the framebuffer is already
>> + * by another driver. See below for an example.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = ...
> 
> Is there really value in allowing/forcing drivers to set up their own
> detach ops? You already make this specific to struct drm_device, an
> implementation that just calls drm_dev_unplug feels like the right thing
> to do?
> 
> Or maybe we should tie this more into the struct device mode and force an
> unload that way? That way devm cleanup would work as one expects, and
> avoid the need for anything specific (hopefully) in this detach callback.
> 
> Just feels a bit like we're reinventing half of the driver model here,
> badly.
> 
>> + *	};
>> + *
>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>> + *	{
>> + *		resource_size_t start, len;
>> + *		struct drm_aperture *ap;
>> + *
>> + *		base = pci_resource_start(pdev, 0);
>> + *		size = pci_resource_len(pdev, 0);
>> + *
>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>> + *		if (IS_ERR(ap))
>> + *			return PTR_ERR(ap);
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + *	static int probe(struct pci_dev *pdev)
>> + *	{
>> + *		struct drm_device *dev;
>> + *		int ret;
>> + *
>> + *		// ... Initialize the device...
>> + *		dev = devm_drm_dev_alloc();
>> + *		...
>> + *
>> + *		// ... and acquire ownership of the framebuffer.
>> + *		ret = acquire_framebuffers(dev, pdev);
>> + *		if (ret)
>> + *			return ret;
>> + *
>> + *		drm_dev_register();
>> + *
>> + *		return 0;
>> + *	}
>> + *
>> + * The generic driver is now subject to forced removal by other drivers. This
>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>> + * for the registered framebuffer range, the DRM core calls struct
>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>> + * detach returned. If the driver supports hotplugging, detach can be treated
>> + * like an unplug event.
>> + *
>> + * .. code-block:: c
>> + *
>> + *	static void detach_from_device(struct drm_device *dev,
>> + *				       resource_size_t base,
>> + *				       resource_size_t size)
>> + *	{
>> + *		// Signal unplug
>> + *		drm_dev_unplug(dev);
>> + *
>> + *		// Maybe do other clean-up operations
>> + *		...
>> + *	}
>> + *
>> + *	static struct drm_aperture_funcs ap_funcs = {
>> + *		.detach = detach_from_device,
>> + *	};
>> + */
>> +
>> +/**
>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>> + *
>> + * This structure has no public fields.
>> + */
>> +struct drm_aperture {
>> +	struct drm_device *dev;
>> +	resource_size_t base;
>> +	resource_size_t size;
>> +
>> +	const struct drm_aperture_funcs *funcs;
>> +
>> +	struct list_head lh;
>> +};
>> +
>> +static LIST_HEAD(drm_apertures);
>> +
>> +static DEFINE_MUTEX(drm_apertures_lock);
>> +
>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>> +		    resource_size_t base2, resource_size_t end2)
>> +{
>> +	return (base1 < end2) && (end1 > base2);
>> +}
>> +
>> +static void devm_aperture_acquire_release(void *data)
>> +{
>> +	struct drm_aperture *ap = data;
>> +	bool detached = !ap->dev;
>> +
>> +	if (!detached)
> 
> Uh this needs a comment that if ap->dev is NULL then we're called from
> drm_aperture_detach_drivers() and hence the lock is already held.
> 
>> +		mutex_lock(&drm_apertures_lock);
> 
> and an
> 
> 	else
> 		locdep_assert_held(&drm_apertures_lock);
> 
> here to check that. I was scratching my head first quite a bit how you'd
> solve the deadlock, this is a neat solution (much simpler than anything I
> came up with in my head). But needs comments.
> 
>> +
>> +	list_del(&ap->lh);
>> +
>> +	if (!detached)
>> +		mutex_unlock(&drm_apertures_lock);
>> +}
>> +
>> +/**
>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>> + * @dev:	the DRM device to own the framebuffer memory
>> + * @base:	the framebuffer's byte offset in physical memory
>> + * @size:	the framebuffer size in bytes
>> + * @funcs:	callback functions
>> + *
>> + * Installs the given device as the new owner. The function fails if the
>> + * framebuffer range, or parts of it, is currently owned by another driver.
>> + * To evict current owners, callers should use
>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>> + * function. Acquired apertures are released automatically if the underlying
>> + * device goes away.
>> + *
>> + * Returns:
>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>> + * errno value otherwise.
>> + */
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs)
>> +{
>> +	size_t end = base + size;
>> +	struct list_head *pos;
>> +	struct drm_aperture *ap;
>> +	int ret;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each(pos, &drm_apertures) {
>> +		ap = container_of(pos, struct drm_aperture, lh);
>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>> +			return ERR_PTR(-EBUSY);
>> +	}
>> +
>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>> +	if (!ap)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ap->dev = dev;
>> +	ap->base = base;
>> +	ap->size = size;
>> +	ap->funcs = funcs;
>> +	INIT_LIST_HEAD(&ap->lh);
>> +
>> +	list_add(&ap->lh, &drm_apertures);
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +
>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return ap;
>> +}
>> +EXPORT_SYMBOL(devm_aperture_acquire);
>> +
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +	resource_size_t end = base + size;
>> +	struct list_head *pos, *n;
>> +
>> +	mutex_lock(&drm_apertures_lock);
>> +
>> +	list_for_each_safe(pos, n, &drm_apertures) {
>> +		struct drm_aperture *ap =
>> +			container_of(pos, struct drm_aperture, lh);
>> +		struct drm_device *dev = ap->dev;
>> +
>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>> +			continue;
>> +
>> +		ap->dev = NULL; /* detach from device */
>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>> +			continue;
>> +		ap->funcs->detach(dev, ap->base, ap->size);
>> +	}
>> +
>> +	mutex_unlock(&drm_apertures_lock);
>> +}
>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> 
> Is this just exported because of the inline functions in the headers? Imo
> better to make them proper functions (they're big after your patch&not
> perf critical, so not good candidates for inlining anyway).
> 
>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>> index 13766efe9517..696cec75ef78 100644
>> --- a/include/drm/drm_aperture.h
>> +++ b/include/drm/drm_aperture.h
>> @@ -4,8 +4,30 @@
>>   #define _DRM_APERTURE_H_
>>   
>>   #include <linux/fb.h>
>> +#include <linux/pci.h>
>>   #include <linux/vgaarb.h>
>>   
>> +struct drm_aperture;
>> +struct drm_device;
>> +
>> +struct drm_aperture_funcs {
>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>> +};
>> +
>> +struct drm_aperture *
>> +devm_aperture_acquire(struct drm_device *dev,
>> +		      resource_size_t base, resource_size_t size,
>> +		      const struct drm_aperture_funcs *funcs);
>> +
>> +#if defined(CONFIG_DRM_APERTURE)
>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>> +#else
>> +static inline void
>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>> +{
>> +}
>> +#endif
>> +
>>   /**
>>    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>    * @a: memory range, users of which are to be removed
>> @@ -20,6 +42,11 @@ static inline int
>>   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>   					      const char *name, bool primary)
>>   {
>> +	int i;
>> +
>> +	for (i = 0; i < a->count; ++i)
>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>> +
>>   #if IS_REACHABLE(CONFIG_FB)
>>   	return remove_conflicting_framebuffers(a, name, primary);
>>   #else
>> @@ -43,7 +70,16 @@ static inline int
>>   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>   						  const char *name)
>>   {
>> -	int ret = 0;
>> +	resource_size_t base, size;
>> +	int bar, ret = 0;
>> +
>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>> +			continue;
>> +		base = pci_resource_start(pdev, bar);
>> +		size = pci_resource_len(pdev, bar);
>> +		drm_aperture_detach_drivers(base, size);
>> +	}
>>   
>>   	/*
>>   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>> -- 
>> 2.30.1
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-09  7:06       ` Thomas Zimmermann
  (?)
@ 2021-04-09  9:22         ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:22 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Daniel Vetter, airlied, maarten.lankhorst, mripard, kraxel,
	corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, hdegoede, bluescreen_avenger, dri-devel,
	linux-doc, virtualization

On Fri, Apr 09, 2021 at 09:06:56AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
> It's a tutorial. In my expectation, everyone just copies the tutorial code
> and fills the gaps.

Sure, but we also have default functions for most common cases, so most
people just end up copypasting the single function call. Feels like
overkill to have a tutorial for that.

Imo tutorial/pseudo-code are good if there's more involved code flow that
many places need to copypaste and customize. Or to show how different
functions work together collectively. This doesn't quite feel like it's
clearing that bar.

And please don't get me wrong, solid docs is great. It's just that I think
we need to have reader's attention span in mind too (and mine personally
might be on the extremely short side here) to make sure our docs are
effective at conveying information.

> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> 
> Is it that easy? simepldrm's detach function has code to synchronize with
> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> I'm all for it.

Uh, I should have looked at the code instead of just asking silly
questions :-)

Now I'm even more scared, and also more convinced that we're recreating a
bad version of some of the core driver model concepts.

I think the ideal option here would be if drm_aperture could unload
(unbind really) the platform driver for us, through the driver model. Then
there's only one place that keeps track whether the driver is unbound or
not. I'm not sure whether this can be done fully generic on a struct
device, or whether we need special code for each type. Since atm we only
have simpledrm we can just specialize on platform_device and it's good
enough.

I think best here would be to Cc: gregkh on this patch and the simpledrm
->detach implementatation, and ask for his feedback as driver model
maintainer. Maybe if you could hack together the platform_device unbind
path as proof of concept would be even better.

Either way, this is really tricky.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  9:22         ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:22 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie,
	Daniel Vetter, sam

On Fri, Apr 09, 2021 at 09:06:56AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
> It's a tutorial. In my expectation, everyone just copies the tutorial code
> and fills the gaps.

Sure, but we also have default functions for most common cases, so most
people just end up copypasting the single function call. Feels like
overkill to have a tutorial for that.

Imo tutorial/pseudo-code are good if there's more involved code flow that
many places need to copypaste and customize. Or to show how different
functions work together collectively. This doesn't quite feel like it's
clearing that bar.

And please don't get me wrong, solid docs is great. It's just that I think
we need to have reader's attention span in mind too (and mine personally
might be on the extremely short side here) to make sure our docs are
effective at conveying information.

> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> 
> Is it that easy? simepldrm's detach function has code to synchronize with
> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> I'm all for it.

Uh, I should have looked at the code instead of just asking silly
questions :-)

Now I'm even more scared, and also more convinced that we're recreating a
bad version of some of the core driver model concepts.

I think the ideal option here would be if drm_aperture could unload
(unbind really) the platform driver for us, through the driver model. Then
there's only one place that keeps track whether the driver is unbound or
not. I'm not sure whether this can be done fully generic on a struct
device, or whether we need special code for each type. Since atm we only
have simpledrm we can just specialize on platform_device and it's good
enough.

I think best here would be to Cc: gregkh on this patch and the simpledrm
->detach implementatation, and ask for his feedback as driver model
maintainer. Maybe if you could hack together the platform_device unbind
path as proof of concept would be even better.

Either way, this is really tricky.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  9:22         ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:22 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam

On Fri, Apr 09, 2021 at 09:06:56AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> 
> It's a tutorial. In my expectation, everyone just copies the tutorial code
> and fills the gaps.

Sure, but we also have default functions for most common cases, so most
people just end up copypasting the single function call. Feels like
overkill to have a tutorial for that.

Imo tutorial/pseudo-code are good if there's more involved code flow that
many places need to copypaste and customize. Or to show how different
functions work together collectively. This doesn't quite feel like it's
clearing that bar.

And please don't get me wrong, solid docs is great. It's just that I think
we need to have reader's attention span in mind too (and mine personally
might be on the extremely short side here) to make sure our docs are
effective at conveying information.

> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> 
> Is it that easy? simepldrm's detach function has code to synchronize with
> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> I'm all for it.

Uh, I should have looked at the code instead of just asking silly
questions :-)

Now I'm even more scared, and also more convinced that we're recreating a
bad version of some of the core driver model concepts.

I think the ideal option here would be if drm_aperture could unload
(unbind really) the platform driver for us, through the driver model. Then
there's only one place that keeps track whether the driver is unbound or
not. I'm not sure whether this can be done fully generic on a struct
device, or whether we need special code for each type. Since atm we only
have simpledrm we can just specialize on platform_device and it's good
enough.

I think best here would be to Cc: gregkh on this patch and the simpledrm
->detach implementatation, and ask for his feedback as driver model
maintainer. Maybe if you could hack together the platform_device unbind
path as proof of concept would be even better.

Either way, this is really tricky.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-09  7:54       ` Thomas Zimmermann
  (?)
@ 2021-04-09  9:29         ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:29 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Daniel Vetter, bluescreen_avenger, geert+renesas, corbet,
	airlied, emil.l.velikov, dri-devel, linux-doc, lgirdwood,
	virtualization, hdegoede, broonie, kraxel, sam

On Fri, Apr 09, 2021 at 09:54:03AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> > > Platform devices might operate on firmware framebuffers, such as VESA or
> > > EFI. Before a native driver for the graphics hardware can take over the
> > > device, it has to remove any platform driver that operates on the firmware
> > > framebuffer. Aperture helpers provide the infrastructure for platform
> > > drivers to acquire firmware framebuffers, and for native drivers to remove
> > > them later on.
> > > 
> > > It works similar to the related fbdev mechanism. During initialization, the
> > > platform driver acquires the firmware framebuffer's I/O memory and provides
> > > a callback to be removed. The native driver later uses this information to
> > > remove any platform driver for it's framebuffer I/O memory.
> > > 
> > > The aperture removal code is integrated into the existing code for removing
> > > conflicting framebuffers, so native drivers use it automatically.
> > > 
> > > v2:
> > > 	* rename plaform helpers to aperture helpers
> > > 	* tie to device lifetime with devm_ functions
> > > 	* removed unsued remove() callback
> > > 	* rename kickout to detach
> > > 	* make struct drm_aperture private
> > > 	* rebase onto existing drm_aperture.h header file
> > > 	* use MIT license only for simplicity
> > > 	* documentation
> > > 
> > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > 
> > Bunch of bikesheds for your considerations below, but overall lgtm.
> > 
> > Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > Cheers, Daniel
> > 
> > > ---
> > >   Documentation/gpu/drm-internals.rst |   6 +
> > >   drivers/gpu/drm/Kconfig             |   7 +
> > >   drivers/gpu/drm/Makefile            |   1 +
> > >   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
> > >   include/drm/drm_aperture.h          |  38 +++-
> > >   5 files changed, 338 insertions(+), 1 deletion(-)
> > >   create mode 100644 drivers/gpu/drm/drm_aperture.c
> > > 
> > > diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> > > index 4c7642d2ca34..06af044c882f 100644
> > > --- a/Documentation/gpu/drm-internals.rst
> > > +++ b/Documentation/gpu/drm-internals.rst
> > > @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
> > >   Managing Ownership of the Framebuffer Aperture
> > >   ----------------------------------------------
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :doc: overview
> > > +
> > >   .. kernel-doc:: include/drm/drm_aperture.h
> > >      :internal:
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :export:
> > > +
> > >   Device Instance and Driver Handling
> > >   -----------------------------------
> > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > > index 1461652921be..b9d3fb91d22d 100644
> > > --- a/drivers/gpu/drm/Kconfig
> > > +++ b/drivers/gpu/drm/Kconfig
> > > @@ -221,6 +221,13 @@ config DRM_SCHED
> > >   	tristate
> > >   	depends on DRM
> > > +config DRM_APERTURE
> > > +	bool
> > > +	depends on DRM
> > > +	help
> > > +	  Controls ownership of graphics apertures. Required to
> > > +	  synchronize with firmware-based drivers.
> > 
> > Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> > code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> > into drm core code, I think either is a good case for this. Everything is
> > its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> > get funny ideas about using these internals ...
> 
> The code lives in the DRM core module. There's no extra ko file. But I'd
> like to keep the Kconfig option. The aperture helpers will only be required
> if there are generic drivers in the kernel and for many systems this is not
> the case.

Imo this kind of optimization is what LTO is for. Having hundreds of
Kconfig symbols just to shave of 2 functions, or something like that, in
each case just doesn't feel like it's justified spending of effort and
complexity. Configuring out entire subsystems, sure, but not individual
pieces like this.

So minimally a new Kconfig like this needs to show in a a) real world
config b) actual relevant savings in terms of bytes. Otherwise it's really
just cargo culting. I also feel like Kconfig symbols for everything is an
appeasement tactic to sneak code int that has seen some resistance about
potential overhead and all that. The cost in maintenance and complexity in
keeping all the combinations working is much, much bigger though. Just
look at the absolute endless amounts of pain that disabling
CONFIG_BACKLIGHT is causing drm drivers. We do not want more of that,
except if it's really solidly justified.

And for the "this saves memory" justification, we've done that for i915 to
kick out support code for old platforms. LTO is what gives you actual
real-world benefits here, since anything else means a bazillion of Kconfig
options, each for minimal gain, resulting in an overall unmaintainable
mess.

</rant>

Cheers, Daniel

> 
> Best regards
> Thomas
> 
> > 
> > > +
> > >   source "drivers/gpu/drm/i2c/Kconfig"
> > >   source "drivers/gpu/drm/arm/Kconfig"
> > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > > index 5eb5bf7c16e3..c9ecb02df0f3 100644
> > > --- a/drivers/gpu/drm/Makefile
> > > +++ b/drivers/gpu/drm/Makefile
> > > @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
> > >   drm-$(CONFIG_PCI) += drm_pci.o
> > >   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> > >   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > > +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
> > >   drm_vram_helper-y := drm_gem_vram_helper.o
> > >   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> > > diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> > > new file mode 100644
> > > index 000000000000..4b02b5fed0a1
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/drm_aperture.c
> > > @@ -0,0 +1,287 @@
> > > +// SPDX-License-Identifier: MIT
> > > +
> > > +#include <linux/device.h>
> > > +#include <linux/list.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include <drm/drm_aperture.h>
> > > +#include <drm/drm_drv.h>
> > > +#include <drm/drm_print.h>
> > > +
> > > +/**
> > > + * DOC: overview
> > > + *
> > > + * A graphics device might be supported by different drivers, but only one
> > > + * driver can be active at any given time. Many systems load a generic
> > > + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> > > + * During later boot stages, they replace the generic driver with a dedicated,
> > > + * hardware-specific driver. To take over the device the dedicated driver
> > > + * first has to remove the generic driver. DRM aperture functions manage
> > > + * ownership of DRM framebuffer memory and hand-over between drivers.
> > > + *
> > > + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> > > + * at the top of their probe function. The function removes any generic
> > > + * driver that is currently associated with the given framebuffer memory.
> > > + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> > > + * example given below.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct apertures_struct *ap;
> > > + *		bool primary = false;
> > > + *		int ret;
> > > + *
> > > + *		ap = alloc_apertures(1);
> > > + *		if (!ap)
> > > + *			return -ENOMEM;
> > > + *
> > > + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> > > + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> > > + *
> > > + *	#ifdef CONFIG_X86
> > > + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> > > + *	#endif
> > > + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> > > + *		kfree(ap);
> > > + *
> > > + *		return ret;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = remove_conflicting_framebuffers(pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> > > + * and let it detect the framebuffer apertures automatically.
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> > 
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  9:29         ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:29 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, Daniel Vetter, sam

On Fri, Apr 09, 2021 at 09:54:03AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> > > Platform devices might operate on firmware framebuffers, such as VESA or
> > > EFI. Before a native driver for the graphics hardware can take over the
> > > device, it has to remove any platform driver that operates on the firmware
> > > framebuffer. Aperture helpers provide the infrastructure for platform
> > > drivers to acquire firmware framebuffers, and for native drivers to remove
> > > them later on.
> > > 
> > > It works similar to the related fbdev mechanism. During initialization, the
> > > platform driver acquires the firmware framebuffer's I/O memory and provides
> > > a callback to be removed. The native driver later uses this information to
> > > remove any platform driver for it's framebuffer I/O memory.
> > > 
> > > The aperture removal code is integrated into the existing code for removing
> > > conflicting framebuffers, so native drivers use it automatically.
> > > 
> > > v2:
> > > 	* rename plaform helpers to aperture helpers
> > > 	* tie to device lifetime with devm_ functions
> > > 	* removed unsued remove() callback
> > > 	* rename kickout to detach
> > > 	* make struct drm_aperture private
> > > 	* rebase onto existing drm_aperture.h header file
> > > 	* use MIT license only for simplicity
> > > 	* documentation
> > > 
> > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > 
> > Bunch of bikesheds for your considerations below, but overall lgtm.
> > 
> > Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > Cheers, Daniel
> > 
> > > ---
> > >   Documentation/gpu/drm-internals.rst |   6 +
> > >   drivers/gpu/drm/Kconfig             |   7 +
> > >   drivers/gpu/drm/Makefile            |   1 +
> > >   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
> > >   include/drm/drm_aperture.h          |  38 +++-
> > >   5 files changed, 338 insertions(+), 1 deletion(-)
> > >   create mode 100644 drivers/gpu/drm/drm_aperture.c
> > > 
> > > diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> > > index 4c7642d2ca34..06af044c882f 100644
> > > --- a/Documentation/gpu/drm-internals.rst
> > > +++ b/Documentation/gpu/drm-internals.rst
> > > @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
> > >   Managing Ownership of the Framebuffer Aperture
> > >   ----------------------------------------------
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :doc: overview
> > > +
> > >   .. kernel-doc:: include/drm/drm_aperture.h
> > >      :internal:
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :export:
> > > +
> > >   Device Instance and Driver Handling
> > >   -----------------------------------
> > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > > index 1461652921be..b9d3fb91d22d 100644
> > > --- a/drivers/gpu/drm/Kconfig
> > > +++ b/drivers/gpu/drm/Kconfig
> > > @@ -221,6 +221,13 @@ config DRM_SCHED
> > >   	tristate
> > >   	depends on DRM
> > > +config DRM_APERTURE
> > > +	bool
> > > +	depends on DRM
> > > +	help
> > > +	  Controls ownership of graphics apertures. Required to
> > > +	  synchronize with firmware-based drivers.
> > 
> > Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> > code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> > into drm core code, I think either is a good case for this. Everything is
> > its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> > get funny ideas about using these internals ...
> 
> The code lives in the DRM core module. There's no extra ko file. But I'd
> like to keep the Kconfig option. The aperture helpers will only be required
> if there are generic drivers in the kernel and for many systems this is not
> the case.

Imo this kind of optimization is what LTO is for. Having hundreds of
Kconfig symbols just to shave of 2 functions, or something like that, in
each case just doesn't feel like it's justified spending of effort and
complexity. Configuring out entire subsystems, sure, but not individual
pieces like this.

So minimally a new Kconfig like this needs to show in a a) real world
config b) actual relevant savings in terms of bytes. Otherwise it's really
just cargo culting. I also feel like Kconfig symbols for everything is an
appeasement tactic to sneak code int that has seen some resistance about
potential overhead and all that. The cost in maintenance and complexity in
keeping all the combinations working is much, much bigger though. Just
look at the absolute endless amounts of pain that disabling
CONFIG_BACKLIGHT is causing drm drivers. We do not want more of that,
except if it's really solidly justified.

And for the "this saves memory" justification, we've done that for i915 to
kick out support code for old platforms. LTO is what gives you actual
real-world benefits here, since anything else means a bazillion of Kconfig
options, each for minimal gain, resulting in an overall unmaintainable
mess.

</rant>

Cheers, Daniel

> 
> Best regards
> Thomas
> 
> > 
> > > +
> > >   source "drivers/gpu/drm/i2c/Kconfig"
> > >   source "drivers/gpu/drm/arm/Kconfig"
> > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > > index 5eb5bf7c16e3..c9ecb02df0f3 100644
> > > --- a/drivers/gpu/drm/Makefile
> > > +++ b/drivers/gpu/drm/Makefile
> > > @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
> > >   drm-$(CONFIG_PCI) += drm_pci.o
> > >   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> > >   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > > +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
> > >   drm_vram_helper-y := drm_gem_vram_helper.o
> > >   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> > > diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> > > new file mode 100644
> > > index 000000000000..4b02b5fed0a1
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/drm_aperture.c
> > > @@ -0,0 +1,287 @@
> > > +// SPDX-License-Identifier: MIT
> > > +
> > > +#include <linux/device.h>
> > > +#include <linux/list.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include <drm/drm_aperture.h>
> > > +#include <drm/drm_drv.h>
> > > +#include <drm/drm_print.h>
> > > +
> > > +/**
> > > + * DOC: overview
> > > + *
> > > + * A graphics device might be supported by different drivers, but only one
> > > + * driver can be active at any given time. Many systems load a generic
> > > + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> > > + * During later boot stages, they replace the generic driver with a dedicated,
> > > + * hardware-specific driver. To take over the device the dedicated driver
> > > + * first has to remove the generic driver. DRM aperture functions manage
> > > + * ownership of DRM framebuffer memory and hand-over between drivers.
> > > + *
> > > + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> > > + * at the top of their probe function. The function removes any generic
> > > + * driver that is currently associated with the given framebuffer memory.
> > > + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> > > + * example given below.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct apertures_struct *ap;
> > > + *		bool primary = false;
> > > + *		int ret;
> > > + *
> > > + *		ap = alloc_apertures(1);
> > > + *		if (!ap)
> > > + *			return -ENOMEM;
> > > + *
> > > + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> > > + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> > > + *
> > > + *	#ifdef CONFIG_X86
> > > + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> > > + *	#endif
> > > + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> > > + *		kfree(ap);
> > > + *
> > > + *		return ret;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = remove_conflicting_framebuffers(pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> > > + * and let it detect the framebuffer apertures automatically.
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> > 
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-09  9:29         ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-09  9:29 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, kraxel, sam

On Fri, Apr 09, 2021 at 09:54:03AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.04.21 um 11:48 schrieb Daniel Vetter:
> > On Thu, Mar 18, 2021 at 11:29:15AM +0100, Thomas Zimmermann wrote:
> > > Platform devices might operate on firmware framebuffers, such as VESA or
> > > EFI. Before a native driver for the graphics hardware can take over the
> > > device, it has to remove any platform driver that operates on the firmware
> > > framebuffer. Aperture helpers provide the infrastructure for platform
> > > drivers to acquire firmware framebuffers, and for native drivers to remove
> > > them later on.
> > > 
> > > It works similar to the related fbdev mechanism. During initialization, the
> > > platform driver acquires the firmware framebuffer's I/O memory and provides
> > > a callback to be removed. The native driver later uses this information to
> > > remove any platform driver for it's framebuffer I/O memory.
> > > 
> > > The aperture removal code is integrated into the existing code for removing
> > > conflicting framebuffers, so native drivers use it automatically.
> > > 
> > > v2:
> > > 	* rename plaform helpers to aperture helpers
> > > 	* tie to device lifetime with devm_ functions
> > > 	* removed unsued remove() callback
> > > 	* rename kickout to detach
> > > 	* make struct drm_aperture private
> > > 	* rebase onto existing drm_aperture.h header file
> > > 	* use MIT license only for simplicity
> > > 	* documentation
> > > 
> > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > 
> > Bunch of bikesheds for your considerations below, but overall lgtm.
> > 
> > Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > Cheers, Daniel
> > 
> > > ---
> > >   Documentation/gpu/drm-internals.rst |   6 +
> > >   drivers/gpu/drm/Kconfig             |   7 +
> > >   drivers/gpu/drm/Makefile            |   1 +
> > >   drivers/gpu/drm/drm_aperture.c      | 287 ++++++++++++++++++++++++++++
> > >   include/drm/drm_aperture.h          |  38 +++-
> > >   5 files changed, 338 insertions(+), 1 deletion(-)
> > >   create mode 100644 drivers/gpu/drm/drm_aperture.c
> > > 
> > > diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst
> > > index 4c7642d2ca34..06af044c882f 100644
> > > --- a/Documentation/gpu/drm-internals.rst
> > > +++ b/Documentation/gpu/drm-internals.rst
> > > @@ -78,9 +78,15 @@ DRM_IOCTL_VERSION ioctl.
> > >   Managing Ownership of the Framebuffer Aperture
> > >   ----------------------------------------------
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :doc: overview
> > > +
> > >   .. kernel-doc:: include/drm/drm_aperture.h
> > >      :internal:
> > > +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c
> > > +   :export:
> > > +
> > >   Device Instance and Driver Handling
> > >   -----------------------------------
> > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > > index 1461652921be..b9d3fb91d22d 100644
> > > --- a/drivers/gpu/drm/Kconfig
> > > +++ b/drivers/gpu/drm/Kconfig
> > > @@ -221,6 +221,13 @@ config DRM_SCHED
> > >   	tristate
> > >   	depends on DRM
> > > +config DRM_APERTURE
> > > +	bool
> > > +	depends on DRM
> > > +	help
> > > +	  Controls ownership of graphics apertures. Required to
> > > +	  synchronize with firmware-based drivers.
> > 
> > Uh I'm not a big fan of Kconfig and .ko modules for every little helper
> > code. Imo just stuff this into the drm kms helpers and done. Or stuff it
> > into drm core code, I think either is a good case for this. Everything is
> > its own module means we need to EXPORT_SYMBOL more stuff, and then drivers
> > get funny ideas about using these internals ...
> 
> The code lives in the DRM core module. There's no extra ko file. But I'd
> like to keep the Kconfig option. The aperture helpers will only be required
> if there are generic drivers in the kernel and for many systems this is not
> the case.

Imo this kind of optimization is what LTO is for. Having hundreds of
Kconfig symbols just to shave of 2 functions, or something like that, in
each case just doesn't feel like it's justified spending of effort and
complexity. Configuring out entire subsystems, sure, but not individual
pieces like this.

So minimally a new Kconfig like this needs to show in a a) real world
config b) actual relevant savings in terms of bytes. Otherwise it's really
just cargo culting. I also feel like Kconfig symbols for everything is an
appeasement tactic to sneak code int that has seen some resistance about
potential overhead and all that. The cost in maintenance and complexity in
keeping all the combinations working is much, much bigger though. Just
look at the absolute endless amounts of pain that disabling
CONFIG_BACKLIGHT is causing drm drivers. We do not want more of that,
except if it's really solidly justified.

And for the "this saves memory" justification, we've done that for i915 to
kick out support code for old platforms. LTO is what gives you actual
real-world benefits here, since anything else means a bazillion of Kconfig
options, each for minimal gain, resulting in an overall unmaintainable
mess.

</rant>

Cheers, Daniel

> 
> Best regards
> Thomas
> 
> > 
> > > +
> > >   source "drivers/gpu/drm/i2c/Kconfig"
> > >   source "drivers/gpu/drm/arm/Kconfig"
> > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > > index 5eb5bf7c16e3..c9ecb02df0f3 100644
> > > --- a/drivers/gpu/drm/Makefile
> > > +++ b/drivers/gpu/drm/Makefile
> > > @@ -32,6 +32,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
> > >   drm-$(CONFIG_PCI) += drm_pci.o
> > >   drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> > >   drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > > +drm-$(CONFIG_DRM_APERTURE) += drm_aperture.o
> > >   drm_vram_helper-y := drm_gem_vram_helper.o
> > >   obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
> > > diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c
> > > new file mode 100644
> > > index 000000000000..4b02b5fed0a1
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/drm_aperture.c
> > > @@ -0,0 +1,287 @@
> > > +// SPDX-License-Identifier: MIT
> > > +
> > > +#include <linux/device.h>
> > > +#include <linux/list.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include <drm/drm_aperture.h>
> > > +#include <drm/drm_drv.h>
> > > +#include <drm/drm_print.h>
> > > +
> > > +/**
> > > + * DOC: overview
> > > + *
> > > + * A graphics device might be supported by different drivers, but only one
> > > + * driver can be active at any given time. Many systems load a generic
> > > + * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
> > > + * During later boot stages, they replace the generic driver with a dedicated,
> > > + * hardware-specific driver. To take over the device the dedicated driver
> > > + * first has to remove the generic driver. DRM aperture functions manage
> > > + * ownership of DRM framebuffer memory and hand-over between drivers.
> > > + *
> > > + * DRM drivers should call drm_fb_helper_remove_conflicting_framebuffers()
> > > + * at the top of their probe function. The function removes any generic
> > > + * driver that is currently associated with the given framebuffer memory.
> > > + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the
> > > + * example given below.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int remove_conflicting_framebuffers(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct apertures_struct *ap;
> > > + *		bool primary = false;
> > > + *		int ret;
> > > + *
> > > + *		ap = alloc_apertures(1);
> > > + *		if (!ap)
> > > + *			return -ENOMEM;
> > > + *
> > > + *		ap->ranges[0].base = pci_resource_start(pdev, 0);
> > > + *		ap->ranges[0].size = pci_resource_len(pdev, 0);
> > > + *
> > > + *	#ifdef CONFIG_X86
> > > + *		primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> > > + *	#endif
> > > + *		ret = drm_fb_helper_remove_conflicting_framebuffers(ap, "example driver", primary);
> > > + *		kfree(ap);
> > > + *
> > > + *		return ret;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = remove_conflicting_framebuffers(pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * For PCI devices it is often sufficient to use drm_fb_helper_remove_conflicting_pci_framebuffers()
> > > + * and let it detect the framebuffer apertures automatically.
> > 
> > Maybe just me, but to avoid overstretching the attention spawn of doc
> > readers I'd avoid this example here. And maybe make the recommendation
> > stronger, e.g. "PCI device drivers can avoid open-coding
> > remove_conflicting_framebuffers() by calling
> > drm_fb_helper_remove_conflicting_pci_framebuffers()."
> > 
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		int ret;
> > > + *
> > > + *		// Remove any generic drivers...
> > > + *		ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "example driver");
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		// ... and initialize the hardware.
> > > + *		...
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * Drivers that are susceptible to being removed be other drivers, such as
> > > + * generic EFI or VESA drivers, have to register themselves as owners of their
> > > + * given framebuffer memory. Ownership of the framebuffer memory is achived
> > > + * by calling devm_aperture_acquire(). On success, the driver is the owner
> > > + * of the framebuffer range. The function fails if the framebuffer is already
> > > + * by another driver. See below for an example.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = ...
> > 
> > Is there really value in allowing/forcing drivers to set up their own
> > detach ops? You already make this specific to struct drm_device, an
> > implementation that just calls drm_dev_unplug feels like the right thing
> > to do?
> > 
> > Or maybe we should tie this more into the struct device mode and force an
> > unload that way? That way devm cleanup would work as one expects, and
> > avoid the need for anything specific (hopefully) in this detach callback.
> > 
> > Just feels a bit like we're reinventing half of the driver model here,
> > badly.
> > 
> > > + *	};
> > > + *
> > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > + *	{
> > > + *		resource_size_t start, len;
> > > + *		struct drm_aperture *ap;
> > > + *
> > > + *		base = pci_resource_start(pdev, 0);
> > > + *		size = pci_resource_len(pdev, 0);
> > > + *
> > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > + *		if (IS_ERR(ap))
> > > + *			return PTR_ERR(ap);
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + *	static int probe(struct pci_dev *pdev)
> > > + *	{
> > > + *		struct drm_device *dev;
> > > + *		int ret;
> > > + *
> > > + *		// ... Initialize the device...
> > > + *		dev = devm_drm_dev_alloc();
> > > + *		...
> > > + *
> > > + *		// ... and acquire ownership of the framebuffer.
> > > + *		ret = acquire_framebuffers(dev, pdev);
> > > + *		if (ret)
> > > + *			return ret;
> > > + *
> > > + *		drm_dev_register();
> > > + *
> > > + *		return 0;
> > > + *	}
> > > + *
> > > + * The generic driver is now subject to forced removal by other drivers. This
> > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > + * for the registered framebuffer range, the DRM core calls struct
> > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > + * like an unplug event.
> > > + *
> > > + * .. code-block:: c
> > > + *
> > > + *	static void detach_from_device(struct drm_device *dev,
> > > + *				       resource_size_t base,
> > > + *				       resource_size_t size)
> > > + *	{
> > > + *		// Signal unplug
> > > + *		drm_dev_unplug(dev);
> > > + *
> > > + *		// Maybe do other clean-up operations
> > > + *		...
> > > + *	}
> > > + *
> > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > + *		.detach = detach_from_device,
> > > + *	};
> > > + */
> > > +
> > > +/**
> > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > + *
> > > + * This structure has no public fields.
> > > + */
> > > +struct drm_aperture {
> > > +	struct drm_device *dev;
> > > +	resource_size_t base;
> > > +	resource_size_t size;
> > > +
> > > +	const struct drm_aperture_funcs *funcs;
> > > +
> > > +	struct list_head lh;
> > > +};
> > > +
> > > +static LIST_HEAD(drm_apertures);
> > > +
> > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > +
> > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > +		    resource_size_t base2, resource_size_t end2)
> > > +{
> > > +	return (base1 < end2) && (end1 > base2);
> > > +}
> > > +
> > > +static void devm_aperture_acquire_release(void *data)
> > > +{
> > > +	struct drm_aperture *ap = data;
> > > +	bool detached = !ap->dev;
> > > +
> > > +	if (!detached)
> > 
> > Uh this needs a comment that if ap->dev is NULL then we're called from
> > drm_aperture_detach_drivers() and hence the lock is already held.
> > 
> > > +		mutex_lock(&drm_apertures_lock);
> > 
> > and an
> > 
> > 	else
> > 		locdep_assert_held(&drm_apertures_lock);
> > 
> > here to check that. I was scratching my head first quite a bit how you'd
> > solve the deadlock, this is a neat solution (much simpler than anything I
> > came up with in my head). But needs comments.
> > 
> > > +
> > > +	list_del(&ap->lh);
> > > +
> > > +	if (!detached)
> > > +		mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +
> > > +/**
> > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > + * @dev:	the DRM device to own the framebuffer memory
> > > + * @base:	the framebuffer's byte offset in physical memory
> > > + * @size:	the framebuffer size in bytes
> > > + * @funcs:	callback functions
> > > + *
> > > + * Installs the given device as the new owner. The function fails if the
> > > + * framebuffer range, or parts of it, is currently owned by another driver.
> > > + * To evict current owners, callers should use
> > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > + * function. Acquired apertures are released automatically if the underlying
> > > + * device goes away.
> > > + *
> > > + * Returns:
> > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > + * errno value otherwise.
> > > + */
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs)
> > > +{
> > > +	size_t end = base + size;
> > > +	struct list_head *pos;
> > > +	struct drm_aperture *ap;
> > > +	int ret;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each(pos, &drm_apertures) {
> > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > +			return ERR_PTR(-EBUSY);
> > > +	}
> > > +
> > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > +	if (!ap)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	ap->dev = dev;
> > > +	ap->base = base;
> > > +	ap->size = size;
> > > +	ap->funcs = funcs;
> > > +	INIT_LIST_HEAD(&ap->lh);
> > > +
> > > +	list_add(&ap->lh, &drm_apertures);
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +
> > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return ap;
> > > +}
> > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > +
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +	resource_size_t end = base + size;
> > > +	struct list_head *pos, *n;
> > > +
> > > +	mutex_lock(&drm_apertures_lock);
> > > +
> > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > +		struct drm_aperture *ap =
> > > +			container_of(pos, struct drm_aperture, lh);
> > > +		struct drm_device *dev = ap->dev;
> > > +
> > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > +			continue;
> > > +
> > > +		ap->dev = NULL; /* detach from device */
> > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > +			continue;
> > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > +	}
> > > +
> > > +	mutex_unlock(&drm_apertures_lock);
> > > +}
> > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > 
> > Is this just exported because of the inline functions in the headers? Imo
> > better to make them proper functions (they're big after your patch&not
> > perf critical, so not good candidates for inlining anyway).
> > 
> > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > index 13766efe9517..696cec75ef78 100644
> > > --- a/include/drm/drm_aperture.h
> > > +++ b/include/drm/drm_aperture.h
> > > @@ -4,8 +4,30 @@
> > >   #define _DRM_APERTURE_H_
> > >   #include <linux/fb.h>
> > > +#include <linux/pci.h>
> > >   #include <linux/vgaarb.h>
> > > +struct drm_aperture;
> > > +struct drm_device;
> > > +
> > > +struct drm_aperture_funcs {
> > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > +};
> > > +
> > > +struct drm_aperture *
> > > +devm_aperture_acquire(struct drm_device *dev,
> > > +		      resource_size_t base, resource_size_t size,
> > > +		      const struct drm_aperture_funcs *funcs);
> > > +
> > > +#if defined(CONFIG_DRM_APERTURE)
> > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > +#else
> > > +static inline void
> > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > +{
> > > +}
> > > +#endif
> > > +
> > >   /**
> > >    * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > >    * @a: memory range, users of which are to be removed
> > > @@ -20,6 +42,11 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > >   					      const char *name, bool primary)
> > >   {
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->count; ++i)
> > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > +
> > >   #if IS_REACHABLE(CONFIG_FB)
> > >   	return remove_conflicting_framebuffers(a, name, primary);
> > >   #else
> > > @@ -43,7 +70,16 @@ static inline int
> > >   drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > >   						  const char *name)
> > >   {
> > > -	int ret = 0;
> > > +	resource_size_t base, size;
> > > +	int bar, ret = 0;
> > > +
> > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > +			continue;
> > > +		base = pci_resource_start(pdev, bar);
> > > +		size = pci_resource_len(pdev, bar);
> > > +		drm_aperture_detach_drivers(base, size);
> > > +	}
> > >   	/*
> > >   	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > -- 
> > > 2.30.1
> > > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-09  9:22         ` Daniel Vetter
  (?)
@ 2021-04-15  6:56           ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  6:56 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: airlied, maarten.lankhorst, mripard, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 11572 bytes --]

Hi

Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>> Is it that easy? simepldrm's detach function has code to synchronize with
>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>> I'm all for it.
> 
> Uh, I should have looked at the code instead of just asking silly
> questions :-)
> 
> Now I'm even more scared, and also more convinced that we're recreating 
a
> bad version of some of the core driver model concepts.
> 
> I think the ideal option here would be if drm_aperture could unload
> (unbind really) the platform driver for us, through the driver model. Then
> there's only one place that keeps track whether the driver is unbound or
> not. I'm not sure whether this can be done fully generic on a struct
> device, or whether we need special code for each type. Since atm we only
> have simpledrm we can just specialize on platform_device and it's good
> enough.

I meanwhile found that calling platform_device_unregister() is the right 
thing to do. It is like a hot-unplug event. It's simple to implement and 
removes the generic device as well. Any memory ranges for the generic 
device are gone as well. Only the native driver's native device will 
remain. That's better than the existing simplefb driver.

Which unregister function to call still driver-specific, so I kept the 
callback.

Best regards
Thomas

> 
> I think best here would be to Cc: gregkh on this patch and the simpledrm
> ->detach implementatation, and ask for his feedback as driver model
> maintainer. Maybe if you could hack together the platform_device unbind
> path as proof of concept would be even better.
> 
> Either way, this is really tricky.
> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> Or maybe we should tie this more into the struct device mode and force an
>>> unload that way? That way devm cleanup would work as one expects, and
>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>
>>> Just feels a bit like we're reinventing half of the driver model here,
>>> badly.
>>>
>>>> + *	};
>>>> + *
>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>>>> + *	{
>>>> + *		resource_size_t start, len;
>>>> + *		struct drm_aperture *ap;
>>>> + *
>>>> + *		base = pci_resource_start(pdev, 0);
>>>> + *		size = pci_resource_len(pdev, 0);
>>>> + *
>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>> + *		if (IS_ERR(ap))
>>>> + *			return PTR_ERR(ap);
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + *	static int probe(struct pci_dev *pdev)
>>>> + *	{
>>>> + *		struct drm_device *dev;
>>>> + *		int ret;
>>>> + *
>>>> + *		// ... Initialize the device...
>>>> + *		dev = devm_drm_dev_alloc();
>>>> + *		...
>>>> + *
>>>> + *		// ... and acquire ownership of the framebuffer.
>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>> + *		if (ret)
>>>> + *			return ret;
>>>> + *
>>>> + *		drm_dev_register();
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>> + * like an unplug event.
>>>> + *
>>>> + * .. code-block:: c
>>>> + *
>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>> + *				       resource_size_t base,
>>>> + *				       resource_size_t size)
>>>> + *	{
>>>> + *		// Signal unplug
>>>> + *		drm_dev_unplug(dev);
>>>> + *
>>>> + *		// Maybe do other clean-up operations
>>>> + *		...
>>>> + *	}
>>>> + *
>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>> + *		.detach = detach_from_device,
>>>> + *	};
>>>> + */
>>>> +
>>>> +/**
>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>> + *
>>>> + * This structure has no public fields.
>>>> + */
>>>> +struct drm_aperture {
>>>> +	struct drm_device *dev;
>>>> +	resource_size_t base;
>>>> +	resource_size_t size;
>>>> +
>>>> +	const struct drm_aperture_funcs *funcs;
>>>> +
>>>> +	struct list_head lh;
>>>> +};
>>>> +
>>>> +static LIST_HEAD(drm_apertures);
>>>> +
>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>> +
>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>> +		    resource_size_t base2, resource_size_t end2)
>>>> +{
>>>> +	return (base1 < end2) && (end1 > base2);
>>>> +}
>>>> +
>>>> +static void devm_aperture_acquire_release(void *data)
>>>> +{
>>>> +	struct drm_aperture *ap = data;
>>>> +	bool detached = !ap->dev;
>>>> +
>>>> +	if (!detached)
>>>
>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>
>>>> +		mutex_lock(&drm_apertures_lock);
>>>
>>> and an
>>>
>>> 	else
>>> 		locdep_assert_held(&drm_apertures_lock);
>>>
>>> here to check that. I was scratching my head first quite a bit how you'd
>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>> came up with in my head). But needs comments.
>>>
>>>> +
>>>> +	list_del(&ap->lh);
>>>> +
>>>> +	if (!detached)
>>>> +		mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +
>>>> +/**
>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>> + * @size:	the framebuffer size in bytes
>>>> + * @funcs:	callback functions
>>>> + *
>>>> + * Installs the given device as the new owner. The function fails if the
>>>> + * framebuffer range, or parts of it, is currently owned by another 
driver.
>>>> + * To evict current owners, callers should use
>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>> + * function. Acquired apertures are released automatically if the underlying
>>>> + * device goes away.
>>>> + *
>>>> + * Returns:
>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>> + * errno value otherwise.
>>>> + */
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs)
>>>> +{
>>>> +	size_t end = base + size;
>>>> +	struct list_head *pos;
>>>> +	struct drm_aperture *ap;
>>>> +	int ret;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each(pos, &drm_apertures) {
>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			return ERR_PTR(-EBUSY);
>>>> +	}
>>>> +
>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>> +	if (!ap)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	ap->dev = dev;
>>>> +	ap->base = base;
>>>> +	ap->size = size;
>>>> +	ap->funcs = funcs;
>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>> +
>>>> +	list_add(&ap->lh, &drm_apertures);
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +
>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>> +	if (ret)
>>>> +		return ERR_PTR(ret);
>>>> +
>>>> +	return ap;
>>>> +}
>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>> +
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +	resource_size_t end = base + size;
>>>> +	struct list_head *pos, *n;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>> +		struct drm_aperture *ap =
>>>> +			container_of(pos, struct drm_aperture, lh);
>>>> +		struct drm_device *dev = ap->dev;
>>>> +
>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			continue;
>>>> +
>>>> +		ap->dev = NULL; /* detach from device */
>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>> +			continue;
>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>> +	}
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>
>>> Is this just exported because of the inline functions in the headers? 
Imo
>>> better to make them proper functions (they're big after your patch&not
>>> perf critical, so not good candidates for inlining anyway).
>>>
>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>> index 13766efe9517..696cec75ef78 100644
>>>> --- a/include/drm/drm_aperture.h
>>>> +++ b/include/drm/drm_aperture.h
>>>> @@ -4,8 +4,30 @@
>>>>    #define _DRM_APERTURE_H_
>>>>    #include <linux/fb.h>
>>>> +#include <linux/pci.h>
>>>>    #include <linux/vgaarb.h>
>>>> +struct drm_aperture;
>>>> +struct drm_device;
>>>> +
>>>> +struct drm_aperture_funcs {
>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>> +};
>>>> +
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs);
>>>> +
>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>> +#else
>>>> +static inline void
>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +}
>>>> +#endif
>>>> +
>>>>    /**
>>>>     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>     * @a: memory range, users of which are to be removed
>>>> @@ -20,6 +42,11 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>    					      const char *name, bool primary)
>>>>    {
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < a->count; ++i)
>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>> +
>>>>    #if IS_REACHABLE(CONFIG_FB)
>>>>    	return remove_conflicting_framebuffers(a, name, primary);
>>>>    #else
>>>> @@ -43,7 +70,16 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>    						  const char *name)
>>>>    {
>>>> -	int ret = 0;
>>>> +	resource_size_t base, size;
>>>> +	int bar, ret = 0;
>>>> +
>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>> +			continue;
>>>> +		base = pci_resource_start(pdev, bar);
>>>> +		size = pci_resource_len(pdev, bar);
>>>> +		drm_aperture_detach_drivers(base, size);
>>>> +	}
>>>>    	/*
>>>>    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15  6:56           ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  6:56 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 11572 bytes --]

Hi

Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>> Is it that easy? simepldrm's detach function has code to synchronize with
>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>> I'm all for it.
> 
> Uh, I should have looked at the code instead of just asking silly
> questions :-)
> 
> Now I'm even more scared, and also more convinced that we're recreating 
a
> bad version of some of the core driver model concepts.
> 
> I think the ideal option here would be if drm_aperture could unload
> (unbind really) the platform driver for us, through the driver model. Then
> there's only one place that keeps track whether the driver is unbound or
> not. I'm not sure whether this can be done fully generic on a struct
> device, or whether we need special code for each type. Since atm we only
> have simpledrm we can just specialize on platform_device and it's good
> enough.

I meanwhile found that calling platform_device_unregister() is the right 
thing to do. It is like a hot-unplug event. It's simple to implement and 
removes the generic device as well. Any memory ranges for the generic 
device are gone as well. Only the native driver's native device will 
remain. That's better than the existing simplefb driver.

Which unregister function to call still driver-specific, so I kept the 
callback.

Best regards
Thomas

> 
> I think best here would be to Cc: gregkh on this patch and the simpledrm
> ->detach implementatation, and ask for his feedback as driver model
> maintainer. Maybe if you could hack together the platform_device unbind
> path as proof of concept would be even better.
> 
> Either way, this is really tricky.
> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> Or maybe we should tie this more into the struct device mode and force an
>>> unload that way? That way devm cleanup would work as one expects, and
>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>
>>> Just feels a bit like we're reinventing half of the driver model here,
>>> badly.
>>>
>>>> + *	};
>>>> + *
>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>>>> + *	{
>>>> + *		resource_size_t start, len;
>>>> + *		struct drm_aperture *ap;
>>>> + *
>>>> + *		base = pci_resource_start(pdev, 0);
>>>> + *		size = pci_resource_len(pdev, 0);
>>>> + *
>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>> + *		if (IS_ERR(ap))
>>>> + *			return PTR_ERR(ap);
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + *	static int probe(struct pci_dev *pdev)
>>>> + *	{
>>>> + *		struct drm_device *dev;
>>>> + *		int ret;
>>>> + *
>>>> + *		// ... Initialize the device...
>>>> + *		dev = devm_drm_dev_alloc();
>>>> + *		...
>>>> + *
>>>> + *		// ... and acquire ownership of the framebuffer.
>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>> + *		if (ret)
>>>> + *			return ret;
>>>> + *
>>>> + *		drm_dev_register();
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>> + * like an unplug event.
>>>> + *
>>>> + * .. code-block:: c
>>>> + *
>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>> + *				       resource_size_t base,
>>>> + *				       resource_size_t size)
>>>> + *	{
>>>> + *		// Signal unplug
>>>> + *		drm_dev_unplug(dev);
>>>> + *
>>>> + *		// Maybe do other clean-up operations
>>>> + *		...
>>>> + *	}
>>>> + *
>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>> + *		.detach = detach_from_device,
>>>> + *	};
>>>> + */
>>>> +
>>>> +/**
>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>> + *
>>>> + * This structure has no public fields.
>>>> + */
>>>> +struct drm_aperture {
>>>> +	struct drm_device *dev;
>>>> +	resource_size_t base;
>>>> +	resource_size_t size;
>>>> +
>>>> +	const struct drm_aperture_funcs *funcs;
>>>> +
>>>> +	struct list_head lh;
>>>> +};
>>>> +
>>>> +static LIST_HEAD(drm_apertures);
>>>> +
>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>> +
>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>> +		    resource_size_t base2, resource_size_t end2)
>>>> +{
>>>> +	return (base1 < end2) && (end1 > base2);
>>>> +}
>>>> +
>>>> +static void devm_aperture_acquire_release(void *data)
>>>> +{
>>>> +	struct drm_aperture *ap = data;
>>>> +	bool detached = !ap->dev;
>>>> +
>>>> +	if (!detached)
>>>
>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>
>>>> +		mutex_lock(&drm_apertures_lock);
>>>
>>> and an
>>>
>>> 	else
>>> 		locdep_assert_held(&drm_apertures_lock);
>>>
>>> here to check that. I was scratching my head first quite a bit how you'd
>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>> came up with in my head). But needs comments.
>>>
>>>> +
>>>> +	list_del(&ap->lh);
>>>> +
>>>> +	if (!detached)
>>>> +		mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +
>>>> +/**
>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>> + * @size:	the framebuffer size in bytes
>>>> + * @funcs:	callback functions
>>>> + *
>>>> + * Installs the given device as the new owner. The function fails if the
>>>> + * framebuffer range, or parts of it, is currently owned by another 
driver.
>>>> + * To evict current owners, callers should use
>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>> + * function. Acquired apertures are released automatically if the underlying
>>>> + * device goes away.
>>>> + *
>>>> + * Returns:
>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>> + * errno value otherwise.
>>>> + */
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs)
>>>> +{
>>>> +	size_t end = base + size;
>>>> +	struct list_head *pos;
>>>> +	struct drm_aperture *ap;
>>>> +	int ret;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each(pos, &drm_apertures) {
>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			return ERR_PTR(-EBUSY);
>>>> +	}
>>>> +
>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>> +	if (!ap)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	ap->dev = dev;
>>>> +	ap->base = base;
>>>> +	ap->size = size;
>>>> +	ap->funcs = funcs;
>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>> +
>>>> +	list_add(&ap->lh, &drm_apertures);
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +
>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>> +	if (ret)
>>>> +		return ERR_PTR(ret);
>>>> +
>>>> +	return ap;
>>>> +}
>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>> +
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +	resource_size_t end = base + size;
>>>> +	struct list_head *pos, *n;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>> +		struct drm_aperture *ap =
>>>> +			container_of(pos, struct drm_aperture, lh);
>>>> +		struct drm_device *dev = ap->dev;
>>>> +
>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			continue;
>>>> +
>>>> +		ap->dev = NULL; /* detach from device */
>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>> +			continue;
>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>> +	}
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>
>>> Is this just exported because of the inline functions in the headers? 
Imo
>>> better to make them proper functions (they're big after your patch&not
>>> perf critical, so not good candidates for inlining anyway).
>>>
>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>> index 13766efe9517..696cec75ef78 100644
>>>> --- a/include/drm/drm_aperture.h
>>>> +++ b/include/drm/drm_aperture.h
>>>> @@ -4,8 +4,30 @@
>>>>    #define _DRM_APERTURE_H_
>>>>    #include <linux/fb.h>
>>>> +#include <linux/pci.h>
>>>>    #include <linux/vgaarb.h>
>>>> +struct drm_aperture;
>>>> +struct drm_device;
>>>> +
>>>> +struct drm_aperture_funcs {
>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>> +};
>>>> +
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs);
>>>> +
>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>> +#else
>>>> +static inline void
>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +}
>>>> +#endif
>>>> +
>>>>    /**
>>>>     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>     * @a: memory range, users of which are to be removed
>>>> @@ -20,6 +42,11 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>    					      const char *name, bool primary)
>>>>    {
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < a->count; ++i)
>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>> +
>>>>    #if IS_REACHABLE(CONFIG_FB)
>>>>    	return remove_conflicting_framebuffers(a, name, primary);
>>>>    #else
>>>> @@ -43,7 +70,16 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>    						  const char *name)
>>>>    {
>>>> -	int ret = 0;
>>>> +	resource_size_t base, size;
>>>> +	int bar, ret = 0;
>>>> +
>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>> +			continue;
>>>> +		base = pci_resource_start(pdev, bar);
>>>> +		size = pci_resource_len(pdev, bar);
>>>> +		drm_aperture_detach_drivers(base, size);
>>>> +	}
>>>>    	/*
>>>>    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15  6:56           ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  6:56 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 11572 bytes --]

Hi

Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>> Is it that easy? simepldrm's detach function has code to synchronize with
>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>> I'm all for it.
> 
> Uh, I should have looked at the code instead of just asking silly
> questions :-)
> 
> Now I'm even more scared, and also more convinced that we're recreating 
a
> bad version of some of the core driver model concepts.
> 
> I think the ideal option here would be if drm_aperture could unload
> (unbind really) the platform driver for us, through the driver model. Then
> there's only one place that keeps track whether the driver is unbound or
> not. I'm not sure whether this can be done fully generic on a struct
> device, or whether we need special code for each type. Since atm we only
> have simpledrm we can just specialize on platform_device and it's good
> enough.

I meanwhile found that calling platform_device_unregister() is the right 
thing to do. It is like a hot-unplug event. It's simple to implement and 
removes the generic device as well. Any memory ranges for the generic 
device are gone as well. Only the native driver's native device will 
remain. That's better than the existing simplefb driver.

Which unregister function to call still driver-specific, so I kept the 
callback.

Best regards
Thomas

> 
> I think best here would be to Cc: gregkh on this patch and the simpledrm
> ->detach implementatation, and ask for his feedback as driver model
> maintainer. Maybe if you could hack together the platform_device unbind
> path as proof of concept would be even better.
> 
> Either way, this is really tricky.
> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> Or maybe we should tie this more into the struct device mode and force an
>>> unload that way? That way devm cleanup would work as one expects, and
>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>
>>> Just feels a bit like we're reinventing half of the driver model here,
>>> badly.
>>>
>>>> + *	};
>>>> + *
>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
>>>> + *	{
>>>> + *		resource_size_t start, len;
>>>> + *		struct drm_aperture *ap;
>>>> + *
>>>> + *		base = pci_resource_start(pdev, 0);
>>>> + *		size = pci_resource_len(pdev, 0);
>>>> + *
>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>> + *		if (IS_ERR(ap))
>>>> + *			return PTR_ERR(ap);
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + *	static int probe(struct pci_dev *pdev)
>>>> + *	{
>>>> + *		struct drm_device *dev;
>>>> + *		int ret;
>>>> + *
>>>> + *		// ... Initialize the device...
>>>> + *		dev = devm_drm_dev_alloc();
>>>> + *		...
>>>> + *
>>>> + *		// ... and acquire ownership of the framebuffer.
>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>> + *		if (ret)
>>>> + *			return ret;
>>>> + *
>>>> + *		drm_dev_register();
>>>> + *
>>>> + *		return 0;
>>>> + *	}
>>>> + *
>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>> + * like an unplug event.
>>>> + *
>>>> + * .. code-block:: c
>>>> + *
>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>> + *				       resource_size_t base,
>>>> + *				       resource_size_t size)
>>>> + *	{
>>>> + *		// Signal unplug
>>>> + *		drm_dev_unplug(dev);
>>>> + *
>>>> + *		// Maybe do other clean-up operations
>>>> + *		...
>>>> + *	}
>>>> + *
>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>> + *		.detach = detach_from_device,
>>>> + *	};
>>>> + */
>>>> +
>>>> +/**
>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>> + *
>>>> + * This structure has no public fields.
>>>> + */
>>>> +struct drm_aperture {
>>>> +	struct drm_device *dev;
>>>> +	resource_size_t base;
>>>> +	resource_size_t size;
>>>> +
>>>> +	const struct drm_aperture_funcs *funcs;
>>>> +
>>>> +	struct list_head lh;
>>>> +};
>>>> +
>>>> +static LIST_HEAD(drm_apertures);
>>>> +
>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>> +
>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>> +		    resource_size_t base2, resource_size_t end2)
>>>> +{
>>>> +	return (base1 < end2) && (end1 > base2);
>>>> +}
>>>> +
>>>> +static void devm_aperture_acquire_release(void *data)
>>>> +{
>>>> +	struct drm_aperture *ap = data;
>>>> +	bool detached = !ap->dev;
>>>> +
>>>> +	if (!detached)
>>>
>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>
>>>> +		mutex_lock(&drm_apertures_lock);
>>>
>>> and an
>>>
>>> 	else
>>> 		locdep_assert_held(&drm_apertures_lock);
>>>
>>> here to check that. I was scratching my head first quite a bit how you'd
>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>> came up with in my head). But needs comments.
>>>
>>>> +
>>>> +	list_del(&ap->lh);
>>>> +
>>>> +	if (!detached)
>>>> +		mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +
>>>> +/**
>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>> + * @size:	the framebuffer size in bytes
>>>> + * @funcs:	callback functions
>>>> + *
>>>> + * Installs the given device as the new owner. The function fails if the
>>>> + * framebuffer range, or parts of it, is currently owned by another 
driver.
>>>> + * To evict current owners, callers should use
>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>> + * function. Acquired apertures are released automatically if the underlying
>>>> + * device goes away.
>>>> + *
>>>> + * Returns:
>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>> + * errno value otherwise.
>>>> + */
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs)
>>>> +{
>>>> +	size_t end = base + size;
>>>> +	struct list_head *pos;
>>>> +	struct drm_aperture *ap;
>>>> +	int ret;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each(pos, &drm_apertures) {
>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			return ERR_PTR(-EBUSY);
>>>> +	}
>>>> +
>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>> +	if (!ap)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	ap->dev = dev;
>>>> +	ap->base = base;
>>>> +	ap->size = size;
>>>> +	ap->funcs = funcs;
>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>> +
>>>> +	list_add(&ap->lh, &drm_apertures);
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +
>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>> +	if (ret)
>>>> +		return ERR_PTR(ret);
>>>> +
>>>> +	return ap;
>>>> +}
>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>> +
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +	resource_size_t end = base + size;
>>>> +	struct list_head *pos, *n;
>>>> +
>>>> +	mutex_lock(&drm_apertures_lock);
>>>> +
>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>> +		struct drm_aperture *ap =
>>>> +			container_of(pos, struct drm_aperture, lh);
>>>> +		struct drm_device *dev = ap->dev;
>>>> +
>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>> +			continue;
>>>> +
>>>> +		ap->dev = NULL; /* detach from device */
>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>> +			continue;
>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>> +	}
>>>> +
>>>> +	mutex_unlock(&drm_apertures_lock);
>>>> +}
>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>
>>> Is this just exported because of the inline functions in the headers? 
Imo
>>> better to make them proper functions (they're big after your patch&not
>>> perf critical, so not good candidates for inlining anyway).
>>>
>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>> index 13766efe9517..696cec75ef78 100644
>>>> --- a/include/drm/drm_aperture.h
>>>> +++ b/include/drm/drm_aperture.h
>>>> @@ -4,8 +4,30 @@
>>>>    #define _DRM_APERTURE_H_
>>>>    #include <linux/fb.h>
>>>> +#include <linux/pci.h>
>>>>    #include <linux/vgaarb.h>
>>>> +struct drm_aperture;
>>>> +struct drm_device;
>>>> +
>>>> +struct drm_aperture_funcs {
>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>> +};
>>>> +
>>>> +struct drm_aperture *
>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>> +		      resource_size_t base, resource_size_t size,
>>>> +		      const struct drm_aperture_funcs *funcs);
>>>> +
>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>> +#else
>>>> +static inline void
>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>> +{
>>>> +}
>>>> +#endif
>>>> +
>>>>    /**
>>>>     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>     * @a: memory range, users of which are to be removed
>>>> @@ -20,6 +42,11 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>    					      const char *name, bool primary)
>>>>    {
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < a->count; ++i)
>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>> +
>>>>    #if IS_REACHABLE(CONFIG_FB)
>>>>    	return remove_conflicting_framebuffers(a, name, primary);
>>>>    #else
>>>> @@ -43,7 +70,16 @@ static inline int
>>>>    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>    						  const char *name)
>>>>    {
>>>> -	int ret = 0;
>>>> +	resource_size_t base, size;
>>>> +	int bar, ret = 0;
>>>> +
>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>> +			continue;
>>>> +		base = pci_resource_start(pdev, bar);
>>>> +		size = pci_resource_len(pdev, bar);
>>>> +		drm_aperture_detach_drivers(base, size);
>>>> +	}
>>>>    	/*
>>>>    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>> -- 
>>>> 2.30.1
>>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-04-08  8:13     ` Maxime Ripard
  (?)
@ 2021-04-15  7:31       ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  7:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: daniel, airlied, maarten.lankhorst, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 1385 bytes --]

Hi

Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Even though it's definitely simpler to review, merging the driver first
> and then the clocks and regulators will break bisection on the platforms
> that rely on them

I'd like to keep the patches separate for now, but can squash patches 6 
to 8 them into one before pushing them. OK?

> 
> Another thing worth considering is also that both drivers will probe if
> they are enabled (which is pretty likely), which is not great :)
> 
> I guess we should make them mutually exclusive through Kconfig

We already have several drivers in fbdev and DRM that handle the same 
hardware. We don't do this for any other pair, why bother now?

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15  7:31       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  7:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, maarten.lankhorst, lgirdwood,
	dri-devel, virtualization, hdegoede, broonie, daniel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 1385 bytes --]

Hi

Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Even though it's definitely simpler to review, merging the driver first
> and then the clocks and regulators will break bisection on the platforms
> that rely on them

I'd like to keep the patches separate for now, but can squash patches 6 
to 8 them into one before pushing them. OK?

> 
> Another thing worth considering is also that both drivers will probe if
> they are enabled (which is pretty likely), which is not great :)
> 
> I guess we should make them mutually exclusive through Kconfig

We already have several drivers in fbdev and DRM that handle the same 
hardware. We don't do this for any other pair, why bother now?

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15  7:31       ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15  7:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, lgirdwood, dri-devel, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 1385 bytes --]

Hi

Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>> Make sure required hardware clocks are enabled while the firmware
>> framebuffer is in use.
>>
>> The basic code has been taken from the simplefb driver and adapted
>> to DRM. Clocks are released automatically via devres helpers.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> Even though it's definitely simpler to review, merging the driver first
> and then the clocks and regulators will break bisection on the platforms
> that rely on them

I'd like to keep the patches separate for now, but can squash patches 6 
to 8 them into one before pushing them. OK?

> 
> Another thing worth considering is also that both drivers will probe if
> they are enabled (which is pretty likely), which is not great :)
> 
> I guess we should make them mutually exclusive through Kconfig

We already have several drivers in fbdev and DRM that handle the same 
hardware. We don't do this for any other pair, why bother now?

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-04-15  7:31       ` Thomas Zimmermann
@ 2021-04-15  9:21         ` Maxime Ripard
  -1 siblings, 0 replies; 103+ messages in thread
From: Maxime Ripard @ 2021-04-15  9:21 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: daniel, airlied, maarten.lankhorst, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization

[-- Attachment #1: Type: text/plain, Size: 1456 bytes --]

Hi,

On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
> Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> > > Make sure required hardware clocks are enabled while the firmware
> > > framebuffer is in use.
> > > 
> > > The basic code has been taken from the simplefb driver and adapted
> > > to DRM. Clocks are released automatically via devres helpers.
> > > 
> > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > 
> > Even though it's definitely simpler to review, merging the driver first
> > and then the clocks and regulators will break bisection on the platforms
> > that rely on them
> 
> I'd like to keep the patches separate for now, but can squash patches 6 to 8
> them into one before pushing them. OK?

Yep, that works for me :)

> > 
> > Another thing worth considering is also that both drivers will probe if
> > they are enabled (which is pretty likely), which is not great :)
> > 
> > I guess we should make them mutually exclusive through Kconfig
> 
> We already have several drivers in fbdev and DRM that handle the same
> hardware. We don't do this for any other pair, why bother now?

Yeah, but simplefb/simpledrm are going to be enabled pretty much
everywhere, as opposed to the other drivers that are more specialized.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15  9:21         ` Maxime Ripard
  0 siblings, 0 replies; 103+ messages in thread
From: Maxime Ripard @ 2021-04-15  9:21 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, lgirdwood, dri-devel, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 1456 bytes --]

Hi,

On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
> Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> > > Make sure required hardware clocks are enabled while the firmware
> > > framebuffer is in use.
> > > 
> > > The basic code has been taken from the simplefb driver and adapted
> > > to DRM. Clocks are released automatically via devres helpers.
> > > 
> > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > 
> > Even though it's definitely simpler to review, merging the driver first
> > and then the clocks and regulators will break bisection on the platforms
> > that rely on them
> 
> I'd like to keep the patches separate for now, but can squash patches 6 to 8
> them into one before pushing them. OK?

Yep, that works for me :)

> > 
> > Another thing worth considering is also that both drivers will probe if
> > they are enabled (which is pretty likely), which is not great :)
> > 
> > I guess we should make them mutually exclusive through Kconfig
> 
> We already have several drivers in fbdev and DRM that handle the same
> hardware. We don't do this for any other pair, why bother now?

Yeah, but simplefb/simpledrm are going to be enabled pretty much
everywhere, as opposed to the other drivers that are more specialized.

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-04-15  9:21         ` Maxime Ripard
  (?)
@ 2021-04-15 11:02           ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 11:02 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: daniel, airlied, maarten.lankhorst, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization


[-- Attachment #1.1: Type: text/plain, Size: 1864 bytes --]

Hi

Am 15.04.21 um 11:21 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
>> Am 08.04.21 um 10:13 schrieb Maxime Ripard:
>>> Hi,
>>>
>>> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>>>> Make sure required hardware clocks are enabled while the firmware
>>>> framebuffer is in use.
>>>>
>>>> The basic code has been taken from the simplefb driver and adapted
>>>> to DRM. Clocks are released automatically via devres helpers.
>>>>
>>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>>>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>>>
>>> Even though it's definitely simpler to review, merging the driver first
>>> and then the clocks and regulators will break bisection on the platforms
>>> that rely on them
>>
>> I'd like to keep the patches separate for now, but can squash patches 6 to 8
>> them into one before pushing them. OK?
> 
> Yep, that works for me :)
> 
>>>
>>> Another thing worth considering is also that both drivers will probe if
>>> they are enabled (which is pretty likely), which is not great :)
>>>
>>> I guess we should make them mutually exclusive through Kconfig
>>
>> We already have several drivers in fbdev and DRM that handle the same
>> hardware. We don't do this for any other pair, why bother now?
> 
> Yeah, but simplefb/simpledrm are going to be enabled pretty much
> everywhere, as opposed to the other drivers that are more specialized.

Well, OK. But I'd like to give simpledrm preference over simplefb. There 
should be an incentive to switch to DRM.

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15 11:02           ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 11:02 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, maarten.lankhorst, lgirdwood,
	dri-devel, virtualization, hdegoede, broonie, daniel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 1864 bytes --]

Hi

Am 15.04.21 um 11:21 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
>> Am 08.04.21 um 10:13 schrieb Maxime Ripard:
>>> Hi,
>>>
>>> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>>>> Make sure required hardware clocks are enabled while the firmware
>>>> framebuffer is in use.
>>>>
>>>> The basic code has been taken from the simplefb driver and adapted
>>>> to DRM. Clocks are released automatically via devres helpers.
>>>>
>>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>>>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>>>
>>> Even though it's definitely simpler to review, merging the driver first
>>> and then the clocks and regulators will break bisection on the platforms
>>> that rely on them
>>
>> I'd like to keep the patches separate for now, but can squash patches 6 to 8
>> them into one before pushing them. OK?
> 
> Yep, that works for me :)
> 
>>>
>>> Another thing worth considering is also that both drivers will probe if
>>> they are enabled (which is pretty likely), which is not great :)
>>>
>>> I guess we should make them mutually exclusive through Kconfig
>>
>> We already have several drivers in fbdev and DRM that handle the same
>> hardware. We don't do this for any other pair, why bother now?
> 
> Yeah, but simplefb/simpledrm are going to be enabled pretty much
> everywhere, as opposed to the other drivers that are more specialized.

Well, OK. But I'd like to give simpledrm preference over simplefb. There 
should be an incentive to switch to DRM.

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15 11:02           ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 11:02 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, lgirdwood, dri-devel, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 1864 bytes --]

Hi

Am 15.04.21 um 11:21 schrieb Maxime Ripard:
> Hi,
> 
> On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
>> Am 08.04.21 um 10:13 schrieb Maxime Ripard:
>>> Hi,
>>>
>>> On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
>>>> Make sure required hardware clocks are enabled while the firmware
>>>> framebuffer is in use.
>>>>
>>>> The basic code has been taken from the simplefb driver and adapted
>>>> to DRM. Clocks are released automatically via devres helpers.
>>>>
>>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>>>> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
>>>
>>> Even though it's definitely simpler to review, merging the driver first
>>> and then the clocks and regulators will break bisection on the platforms
>>> that rely on them
>>
>> I'd like to keep the patches separate for now, but can squash patches 6 to 8
>> them into one before pushing them. OK?
> 
> Yep, that works for me :)
> 
>>>
>>> Another thing worth considering is also that both drivers will probe if
>>> they are enabled (which is pretty likely), which is not great :)
>>>
>>> I guess we should make them mutually exclusive through Kconfig
>>
>> We already have several drivers in fbdev and DRM that handle the same
>> hardware. We don't do this for any other pair, why bother now?
> 
> Yeah, but simplefb/simpledrm are going to be enabled pretty much
> everywhere, as opposed to the other drivers that are more specialized.

Well, OK. But I'd like to give simpledrm preference over simplefb. There 
should be an incentive to switch to DRM.

Best regards
Thomas

> 
> Maxime
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
  2021-04-15 11:02           ` Thomas Zimmermann
@ 2021-04-15 12:11             ` maxime
  -1 siblings, 0 replies; 103+ messages in thread
From: maxime @ 2021-04-15 12:11 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: daniel, airlied, maarten.lankhorst, kraxel, corbet, lgirdwood,
	broonie, sam, robh, emil.l.velikov, geert+renesas, hdegoede,
	bluescreen_avenger, dri-devel, linux-doc, virtualization

[-- Attachment #1: Type: text/plain, Size: 1883 bytes --]

On Thu, Apr 15, 2021 at 01:02:44PM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 15.04.21 um 11:21 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
> > > Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> > > > Hi,
> > > > 
> > > > On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> > > > > Make sure required hardware clocks are enabled while the firmware
> > > > > framebuffer is in use.
> > > > > 
> > > > > The basic code has been taken from the simplefb driver and adapted
> > > > > to DRM. Clocks are released automatically via devres helpers.
> > > > > 
> > > > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > > > 
> > > > Even though it's definitely simpler to review, merging the driver first
> > > > and then the clocks and regulators will break bisection on the platforms
> > > > that rely on them
> > > 
> > > I'd like to keep the patches separate for now, but can squash patches 6 to 8
> > > them into one before pushing them. OK?
> > 
> > Yep, that works for me :)
> > 
> > > > 
> > > > Another thing worth considering is also that both drivers will probe if
> > > > they are enabled (which is pretty likely), which is not great :)
> > > > 
> > > > I guess we should make them mutually exclusive through Kconfig
> > > 
> > > We already have several drivers in fbdev and DRM that handle the same
> > > hardware. We don't do this for any other pair, why bother now?
> > 
> > Yeah, but simplefb/simpledrm are going to be enabled pretty much
> > everywhere, as opposed to the other drivers that are more specialized.
> 
> Well, OK. But I'd like to give simpledrm preference over simplefb. There
> should be an incentive to switch to DRM.

Yeah that makes total sense :)

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node
@ 2021-04-15 12:11             ` maxime
  0 siblings, 0 replies; 103+ messages in thread
From: maxime @ 2021-04-15 12:11 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, linux-doc, lgirdwood, dri-devel, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 1883 bytes --]

On Thu, Apr 15, 2021 at 01:02:44PM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 15.04.21 um 11:21 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Thu, Apr 15, 2021 at 09:31:01AM +0200, Thomas Zimmermann wrote:
> > > Am 08.04.21 um 10:13 schrieb Maxime Ripard:
> > > > Hi,
> > > > 
> > > > On Thu, Mar 18, 2021 at 11:29:19AM +0100, Thomas Zimmermann wrote:
> > > > > Make sure required hardware clocks are enabled while the firmware
> > > > > framebuffer is in use.
> > > > > 
> > > > > The basic code has been taken from the simplefb driver and adapted
> > > > > to DRM. Clocks are released automatically via devres helpers.
> > > > > 
> > > > > Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > > > > Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> > > > 
> > > > Even though it's definitely simpler to review, merging the driver first
> > > > and then the clocks and regulators will break bisection on the platforms
> > > > that rely on them
> > > 
> > > I'd like to keep the patches separate for now, but can squash patches 6 to 8
> > > them into one before pushing them. OK?
> > 
> > Yep, that works for me :)
> > 
> > > > 
> > > > Another thing worth considering is also that both drivers will probe if
> > > > they are enabled (which is pretty likely), which is not great :)
> > > > 
> > > > I guess we should make them mutually exclusive through Kconfig
> > > 
> > > We already have several drivers in fbdev and DRM that handle the same
> > > hardware. We don't do this for any other pair, why bother now?
> > 
> > Yeah, but simplefb/simpledrm are going to be enabled pretty much
> > everywhere, as opposed to the other drivers that are more specialized.
> 
> Well, OK. But I'd like to give simpledrm preference over simplefb. There
> should be an incentive to switch to DRM.

Yeah that makes total sense :)

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-15  6:56           ` Thomas Zimmermann
  (?)
@ 2021-04-15 12:57             ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-15 12:57 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Daniel Vetter, airlied, maarten.lankhorst, mripard, kraxel,
	corbet, lgirdwood, broonie, sam, robh, emil.l.velikov,
	geert+renesas, hdegoede, bluescreen_avenger, dri-devel,
	linux-doc, virtualization

On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > Is it that easy? simepldrm's detach function has code to synchronize with
> > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > I'm all for it.
> > 
> > Uh, I should have looked at the code instead of just asking silly
> > questions :-)
> > 
> > Now I'm even more scared, and also more convinced that we're recreating
> a
> > bad version of some of the core driver model concepts.
> > 
> > I think the ideal option here would be if drm_aperture could unload
> > (unbind really) the platform driver for us, through the driver model. Then
> > there's only one place that keeps track whether the driver is unbound or
> > not. I'm not sure whether this can be done fully generic on a struct
> > device, or whether we need special code for each type. Since atm we only
> > have simpledrm we can just specialize on platform_device and it's good
> > enough.
> 
> I meanwhile found that calling platform_device_unregister() is the right
> thing to do. It is like a hot-unplug event. It's simple to implement and
> removes the generic device as well. Any memory ranges for the generic device
> are gone as well. Only the native driver's native device will remain. That's
> better than the existing simplefb driver.

That sounds great.

> Which unregister function to call still driver-specific, so I kept the
> callback.

Could we have the callback in core code, and you do something like
drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
whatever, although tbh I'm not sure we ever get anything else than
platform). That function can do a runtime check that drm_device->dev is
actually a platform dev.

Another idea: Do the runtime casting in the core without anything? Atm we
have platform that needs support, maybe pci device, so we could easily
extend this and just let it do the right thing. Then no callback is
needed. I.e.

	if (is_platform_dev(drm_device->dev))
		platform_device_unregister(drm_device->dev);
	else
		WARN(1, "not yet implemented\n");

or something like that.

I just find the callback to essentially unregister a device a bit
redundant.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > ->detach implementatation, and ask for his feedback as driver model
> > maintainer. Maybe if you could hack together the platform_device unbind
> > path as proof of concept would be even better.
> > 
> > Either way, this is really tricky.
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > Or maybe we should tie this more into the struct device mode and force an
> > > > unload that way? That way devm cleanup would work as one expects, and
> > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > 
> > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > badly.
> > > > 
> > > > > + *	};
> > > > > + *
> > > > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		resource_size_t start, len;
> > > > > + *		struct drm_aperture *ap;
> > > > > + *
> > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > + *
> > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > + *		if (IS_ERR(ap))
> > > > > + *			return PTR_ERR(ap);
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		struct drm_device *dev;
> > > > > + *		int ret;
> > > > > + *
> > > > > + *		// ... Initialize the device...
> > > > > + *		dev = devm_drm_dev_alloc();
> > > > > + *		...
> > > > > + *
> > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > + *		if (ret)
> > > > > + *			return ret;
> > > > > + *
> > > > > + *		drm_dev_register();
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > + * like an unplug event.
> > > > > + *
> > > > > + * .. code-block:: c
> > > > > + *
> > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > + *				       resource_size_t base,
> > > > > + *				       resource_size_t size)
> > > > > + *	{
> > > > > + *		// Signal unplug
> > > > > + *		drm_dev_unplug(dev);
> > > > > + *
> > > > > + *		// Maybe do other clean-up operations
> > > > > + *		...
> > > > > + *	}
> > > > > + *
> > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > + *		.detach = detach_from_device,
> > > > > + *	};
> > > > > + */
> > > > > +
> > > > > +/**
> > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > + *
> > > > > + * This structure has no public fields.
> > > > > + */
> > > > > +struct drm_aperture {
> > > > > +	struct drm_device *dev;
> > > > > +	resource_size_t base;
> > > > > +	resource_size_t size;
> > > > > +
> > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > +
> > > > > +	struct list_head lh;
> > > > > +};
> > > > > +
> > > > > +static LIST_HEAD(drm_apertures);
> > > > > +
> > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > +
> > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > +{
> > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > +}
> > > > > +
> > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > +{
> > > > > +	struct drm_aperture *ap = data;
> > > > > +	bool detached = !ap->dev;
> > > > > +
> > > > > +	if (!detached)
> > > > 
> > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > 
> > > > > +		mutex_lock(&drm_apertures_lock);
> > > > 
> > > > and an
> > > > 
> > > > 	else
> > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > 
> > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > came up with in my head). But needs comments.
> > > > 
> > > > > +
> > > > > +	list_del(&ap->lh);
> > > > > +
> > > > > +	if (!detached)
> > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > + * @size:	the framebuffer size in bytes
> > > > > + * @funcs:	callback functions
> > > > > + *
> > > > > + * Installs the given device as the new owner. The function fails if the
> > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > another
> driver.
> > > > > + * To evict current owners, callers should use
> > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > + * function. Acquired apertures are released automatically if the underlying
> > > > > + * device goes away.
> > > > > + *
> > > > > + * Returns:
> > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > + * errno value otherwise.
> > > > > + */
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > +{
> > > > > +	size_t end = base + size;
> > > > > +	struct list_head *pos;
> > > > > +	struct drm_aperture *ap;
> > > > > +	int ret;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			return ERR_PTR(-EBUSY);
> > > > > +	}
> > > > > +
> > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > +	if (!ap)
> > > > > +		return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +	ap->dev = dev;
> > > > > +	ap->base = base;
> > > > > +	ap->size = size;
> > > > > +	ap->funcs = funcs;
> > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > +
> > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +
> > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > +	if (ret)
> > > > > +		return ERR_PTR(ret);
> > > > > +
> > > > > +	return ap;
> > > > > +}
> > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > +
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +	resource_size_t end = base + size;
> > > > > +	struct list_head *pos, *n;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > +		struct drm_aperture *ap =
> > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > +		struct drm_device *dev = ap->dev;
> > > > > +
> > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			continue;
> > > > > +
> > > > > +		ap->dev = NULL; /* detach from device */
> > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > +			continue;
> > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > +	}
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > 
> > > > Is this just exported because of the inline functions in the
> > > > headers?
> Imo
> > > > better to make them proper functions (they're big after your patch&not
> > > > perf critical, so not good candidates for inlining anyway).
> > > > 
> > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > index 13766efe9517..696cec75ef78 100644
> > > > > --- a/include/drm/drm_aperture.h
> > > > > +++ b/include/drm/drm_aperture.h
> > > > > @@ -4,8 +4,30 @@
> > > > >    #define _DRM_APERTURE_H_
> > > > >    #include <linux/fb.h>
> > > > > +#include <linux/pci.h>
> > > > >    #include <linux/vgaarb.h>
> > > > > +struct drm_aperture;
> > > > > +struct drm_device;
> > > > > +
> > > > > +struct drm_aperture_funcs {
> > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > +};
> > > > > +
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > +
> > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > +#else
> > > > > +static inline void
> > > > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +}
> > > > > +#endif
> > > > > +
> > > > >    /**
> > > > >     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > >     * @a: memory range, users of which are to be removed
> > > > > @@ -20,6 +42,11 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > >    					      const char *name, bool primary)
> > > > >    {
> > > > > +	int i;
> > > > > +
> > > > > +	for (i = 0; i < a->count; ++i)
> > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > +
> > > > >    #if IS_REACHABLE(CONFIG_FB)
> > > > >    	return remove_conflicting_framebuffers(a, name, primary);
> > > > >    #else
> > > > > @@ -43,7 +70,16 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > >    						  const char *name)
> > > > >    {
> > > > > -	int ret = 0;
> > > > > +	resource_size_t base, size;
> > > > > +	int bar, ret = 0;
> > > > > +
> > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > +			continue;
> > > > > +		base = pci_resource_start(pdev, bar);
> > > > > +		size = pci_resource_len(pdev, bar);
> > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > +	}
> > > > >    	/*
> > > > >    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > -- 
> > > > > 2.30.1
> > > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15 12:57             ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-15 12:57 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: robh, bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, maarten.lankhorst,
	lgirdwood, mripard, virtualization, hdegoede, broonie,
	Daniel Vetter, sam

On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > Is it that easy? simepldrm's detach function has code to synchronize with
> > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > I'm all for it.
> > 
> > Uh, I should have looked at the code instead of just asking silly
> > questions :-)
> > 
> > Now I'm even more scared, and also more convinced that we're recreating
> a
> > bad version of some of the core driver model concepts.
> > 
> > I think the ideal option here would be if drm_aperture could unload
> > (unbind really) the platform driver for us, through the driver model. Then
> > there's only one place that keeps track whether the driver is unbound or
> > not. I'm not sure whether this can be done fully generic on a struct
> > device, or whether we need special code for each type. Since atm we only
> > have simpledrm we can just specialize on platform_device and it's good
> > enough.
> 
> I meanwhile found that calling platform_device_unregister() is the right
> thing to do. It is like a hot-unplug event. It's simple to implement and
> removes the generic device as well. Any memory ranges for the generic device
> are gone as well. Only the native driver's native device will remain. That's
> better than the existing simplefb driver.

That sounds great.

> Which unregister function to call still driver-specific, so I kept the
> callback.

Could we have the callback in core code, and you do something like
drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
whatever, although tbh I'm not sure we ever get anything else than
platform). That function can do a runtime check that drm_device->dev is
actually a platform dev.

Another idea: Do the runtime casting in the core without anything? Atm we
have platform that needs support, maybe pci device, so we could easily
extend this and just let it do the right thing. Then no callback is
needed. I.e.

	if (is_platform_dev(drm_device->dev))
		platform_device_unregister(drm_device->dev);
	else
		WARN(1, "not yet implemented\n");

or something like that.

I just find the callback to essentially unregister a device a bit
redundant.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > ->detach implementatation, and ask for his feedback as driver model
> > maintainer. Maybe if you could hack together the platform_device unbind
> > path as proof of concept would be even better.
> > 
> > Either way, this is really tricky.
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > Or maybe we should tie this more into the struct device mode and force an
> > > > unload that way? That way devm cleanup would work as one expects, and
> > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > 
> > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > badly.
> > > > 
> > > > > + *	};
> > > > > + *
> > > > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		resource_size_t start, len;
> > > > > + *		struct drm_aperture *ap;
> > > > > + *
> > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > + *
> > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > + *		if (IS_ERR(ap))
> > > > > + *			return PTR_ERR(ap);
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		struct drm_device *dev;
> > > > > + *		int ret;
> > > > > + *
> > > > > + *		// ... Initialize the device...
> > > > > + *		dev = devm_drm_dev_alloc();
> > > > > + *		...
> > > > > + *
> > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > + *		if (ret)
> > > > > + *			return ret;
> > > > > + *
> > > > > + *		drm_dev_register();
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > + * like an unplug event.
> > > > > + *
> > > > > + * .. code-block:: c
> > > > > + *
> > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > + *				       resource_size_t base,
> > > > > + *				       resource_size_t size)
> > > > > + *	{
> > > > > + *		// Signal unplug
> > > > > + *		drm_dev_unplug(dev);
> > > > > + *
> > > > > + *		// Maybe do other clean-up operations
> > > > > + *		...
> > > > > + *	}
> > > > > + *
> > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > + *		.detach = detach_from_device,
> > > > > + *	};
> > > > > + */
> > > > > +
> > > > > +/**
> > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > + *
> > > > > + * This structure has no public fields.
> > > > > + */
> > > > > +struct drm_aperture {
> > > > > +	struct drm_device *dev;
> > > > > +	resource_size_t base;
> > > > > +	resource_size_t size;
> > > > > +
> > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > +
> > > > > +	struct list_head lh;
> > > > > +};
> > > > > +
> > > > > +static LIST_HEAD(drm_apertures);
> > > > > +
> > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > +
> > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > +{
> > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > +}
> > > > > +
> > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > +{
> > > > > +	struct drm_aperture *ap = data;
> > > > > +	bool detached = !ap->dev;
> > > > > +
> > > > > +	if (!detached)
> > > > 
> > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > 
> > > > > +		mutex_lock(&drm_apertures_lock);
> > > > 
> > > > and an
> > > > 
> > > > 	else
> > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > 
> > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > came up with in my head). But needs comments.
> > > > 
> > > > > +
> > > > > +	list_del(&ap->lh);
> > > > > +
> > > > > +	if (!detached)
> > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > + * @size:	the framebuffer size in bytes
> > > > > + * @funcs:	callback functions
> > > > > + *
> > > > > + * Installs the given device as the new owner. The function fails if the
> > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > another
> driver.
> > > > > + * To evict current owners, callers should use
> > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > + * function. Acquired apertures are released automatically if the underlying
> > > > > + * device goes away.
> > > > > + *
> > > > > + * Returns:
> > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > + * errno value otherwise.
> > > > > + */
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > +{
> > > > > +	size_t end = base + size;
> > > > > +	struct list_head *pos;
> > > > > +	struct drm_aperture *ap;
> > > > > +	int ret;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			return ERR_PTR(-EBUSY);
> > > > > +	}
> > > > > +
> > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > +	if (!ap)
> > > > > +		return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +	ap->dev = dev;
> > > > > +	ap->base = base;
> > > > > +	ap->size = size;
> > > > > +	ap->funcs = funcs;
> > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > +
> > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +
> > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > +	if (ret)
> > > > > +		return ERR_PTR(ret);
> > > > > +
> > > > > +	return ap;
> > > > > +}
> > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > +
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +	resource_size_t end = base + size;
> > > > > +	struct list_head *pos, *n;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > +		struct drm_aperture *ap =
> > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > +		struct drm_device *dev = ap->dev;
> > > > > +
> > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			continue;
> > > > > +
> > > > > +		ap->dev = NULL; /* detach from device */
> > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > +			continue;
> > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > +	}
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > 
> > > > Is this just exported because of the inline functions in the
> > > > headers?
> Imo
> > > > better to make them proper functions (they're big after your patch&not
> > > > perf critical, so not good candidates for inlining anyway).
> > > > 
> > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > index 13766efe9517..696cec75ef78 100644
> > > > > --- a/include/drm/drm_aperture.h
> > > > > +++ b/include/drm/drm_aperture.h
> > > > > @@ -4,8 +4,30 @@
> > > > >    #define _DRM_APERTURE_H_
> > > > >    #include <linux/fb.h>
> > > > > +#include <linux/pci.h>
> > > > >    #include <linux/vgaarb.h>
> > > > > +struct drm_aperture;
> > > > > +struct drm_device;
> > > > > +
> > > > > +struct drm_aperture_funcs {
> > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > +};
> > > > > +
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > +
> > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > +#else
> > > > > +static inline void
> > > > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +}
> > > > > +#endif
> > > > > +
> > > > >    /**
> > > > >     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > >     * @a: memory range, users of which are to be removed
> > > > > @@ -20,6 +42,11 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > >    					      const char *name, bool primary)
> > > > >    {
> > > > > +	int i;
> > > > > +
> > > > > +	for (i = 0; i < a->count; ++i)
> > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > +
> > > > >    #if IS_REACHABLE(CONFIG_FB)
> > > > >    	return remove_conflicting_framebuffers(a, name, primary);
> > > > >    #else
> > > > > @@ -43,7 +70,16 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > >    						  const char *name)
> > > > >    {
> > > > > -	int ret = 0;
> > > > > +	resource_size_t base, size;
> > > > > +	int bar, ret = 0;
> > > > > +
> > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > +			continue;
> > > > > +		base = pci_resource_start(pdev, bar);
> > > > > +		size = pci_resource_len(pdev, bar);
> > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > +	}
> > > > >    	/*
> > > > >    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > -- 
> > > > > 2.30.1
> > > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15 12:57             ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-15 12:57 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam

On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > Is it that easy? simepldrm's detach function has code to synchronize with
> > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > I'm all for it.
> > 
> > Uh, I should have looked at the code instead of just asking silly
> > questions :-)
> > 
> > Now I'm even more scared, and also more convinced that we're recreating
> a
> > bad version of some of the core driver model concepts.
> > 
> > I think the ideal option here would be if drm_aperture could unload
> > (unbind really) the platform driver for us, through the driver model. Then
> > there's only one place that keeps track whether the driver is unbound or
> > not. I'm not sure whether this can be done fully generic on a struct
> > device, or whether we need special code for each type. Since atm we only
> > have simpledrm we can just specialize on platform_device and it's good
> > enough.
> 
> I meanwhile found that calling platform_device_unregister() is the right
> thing to do. It is like a hot-unplug event. It's simple to implement and
> removes the generic device as well. Any memory ranges for the generic device
> are gone as well. Only the native driver's native device will remain. That's
> better than the existing simplefb driver.

That sounds great.

> Which unregister function to call still driver-specific, so I kept the
> callback.

Could we have the callback in core code, and you do something like
drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
whatever, although tbh I'm not sure we ever get anything else than
platform). That function can do a runtime check that drm_device->dev is
actually a platform dev.

Another idea: Do the runtime casting in the core without anything? Atm we
have platform that needs support, maybe pci device, so we could easily
extend this and just let it do the right thing. Then no callback is
needed. I.e.

	if (is_platform_dev(drm_device->dev))
		platform_device_unregister(drm_device->dev);
	else
		WARN(1, "not yet implemented\n");

or something like that.

I just find the callback to essentially unregister a device a bit
redundant.
-Daniel

> 
> Best regards
> Thomas
> 
> > 
> > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > ->detach implementatation, and ask for his feedback as driver model
> > maintainer. Maybe if you could hack together the platform_device unbind
> > path as proof of concept would be even better.
> > 
> > Either way, this is really tricky.
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > Or maybe we should tie this more into the struct device mode and force an
> > > > unload that way? That way devm cleanup would work as one expects, and
> > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > 
> > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > badly.
> > > > 
> > > > > + *	};
> > > > > + *
> > > > > + *	static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		resource_size_t start, len;
> > > > > + *		struct drm_aperture *ap;
> > > > > + *
> > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > + *
> > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > + *		if (IS_ERR(ap))
> > > > > + *			return PTR_ERR(ap);
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > + *	{
> > > > > + *		struct drm_device *dev;
> > > > > + *		int ret;
> > > > > + *
> > > > > + *		// ... Initialize the device...
> > > > > + *		dev = devm_drm_dev_alloc();
> > > > > + *		...
> > > > > + *
> > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > + *		if (ret)
> > > > > + *			return ret;
> > > > > + *
> > > > > + *		drm_dev_register();
> > > > > + *
> > > > > + *		return 0;
> > > > > + *	}
> > > > > + *
> > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > + * like an unplug event.
> > > > > + *
> > > > > + * .. code-block:: c
> > > > > + *
> > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > + *				       resource_size_t base,
> > > > > + *				       resource_size_t size)
> > > > > + *	{
> > > > > + *		// Signal unplug
> > > > > + *		drm_dev_unplug(dev);
> > > > > + *
> > > > > + *		// Maybe do other clean-up operations
> > > > > + *		...
> > > > > + *	}
> > > > > + *
> > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > + *		.detach = detach_from_device,
> > > > > + *	};
> > > > > + */
> > > > > +
> > > > > +/**
> > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > + *
> > > > > + * This structure has no public fields.
> > > > > + */
> > > > > +struct drm_aperture {
> > > > > +	struct drm_device *dev;
> > > > > +	resource_size_t base;
> > > > > +	resource_size_t size;
> > > > > +
> > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > +
> > > > > +	struct list_head lh;
> > > > > +};
> > > > > +
> > > > > +static LIST_HEAD(drm_apertures);
> > > > > +
> > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > +
> > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > +{
> > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > +}
> > > > > +
> > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > +{
> > > > > +	struct drm_aperture *ap = data;
> > > > > +	bool detached = !ap->dev;
> > > > > +
> > > > > +	if (!detached)
> > > > 
> > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > 
> > > > > +		mutex_lock(&drm_apertures_lock);
> > > > 
> > > > and an
> > > > 
> > > > 	else
> > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > 
> > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > came up with in my head). But needs comments.
> > > > 
> > > > > +
> > > > > +	list_del(&ap->lh);
> > > > > +
> > > > > +	if (!detached)
> > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver.
> > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > + * @size:	the framebuffer size in bytes
> > > > > + * @funcs:	callback functions
> > > > > + *
> > > > > + * Installs the given device as the new owner. The function fails if the
> > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > another
> driver.
> > > > > + * To evict current owners, callers should use
> > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > + * function. Acquired apertures are released automatically if the underlying
> > > > > + * device goes away.
> > > > > + *
> > > > > + * Returns:
> > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > + * errno value otherwise.
> > > > > + */
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > +{
> > > > > +	size_t end = base + size;
> > > > > +	struct list_head *pos;
> > > > > +	struct drm_aperture *ap;
> > > > > +	int ret;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			return ERR_PTR(-EBUSY);
> > > > > +	}
> > > > > +
> > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > +	if (!ap)
> > > > > +		return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +	ap->dev = dev;
> > > > > +	ap->base = base;
> > > > > +	ap->size = size;
> > > > > +	ap->funcs = funcs;
> > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > +
> > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +
> > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > +	if (ret)
> > > > > +		return ERR_PTR(ret);
> > > > > +
> > > > > +	return ap;
> > > > > +}
> > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > +
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +	resource_size_t end = base + size;
> > > > > +	struct list_head *pos, *n;
> > > > > +
> > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > +
> > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > +		struct drm_aperture *ap =
> > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > +		struct drm_device *dev = ap->dev;
> > > > > +
> > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > +			continue;
> > > > > +
> > > > > +		ap->dev = NULL; /* detach from device */
> > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > +			continue;
> > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > +	}
> > > > > +
> > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > +}
> > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > 
> > > > Is this just exported because of the inline functions in the
> > > > headers?
> Imo
> > > > better to make them proper functions (they're big after your patch&not
> > > > perf critical, so not good candidates for inlining anyway).
> > > > 
> > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > index 13766efe9517..696cec75ef78 100644
> > > > > --- a/include/drm/drm_aperture.h
> > > > > +++ b/include/drm/drm_aperture.h
> > > > > @@ -4,8 +4,30 @@
> > > > >    #define _DRM_APERTURE_H_
> > > > >    #include <linux/fb.h>
> > > > > +#include <linux/pci.h>
> > > > >    #include <linux/vgaarb.h>
> > > > > +struct drm_aperture;
> > > > > +struct drm_device;
> > > > > +
> > > > > +struct drm_aperture_funcs {
> > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > +};
> > > > > +
> > > > > +struct drm_aperture *
> > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > +		      resource_size_t base, resource_size_t size,
> > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > +
> > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > +#else
> > > > > +static inline void
> > > > > +drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > +{
> > > > > +}
> > > > > +#endif
> > > > > +
> > > > >    /**
> > > > >     * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > >     * @a: memory range, users of which are to be removed
> > > > > @@ -20,6 +42,11 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > >    					      const char *name, bool primary)
> > > > >    {
> > > > > +	int i;
> > > > > +
> > > > > +	for (i = 0; i < a->count; ++i)
> > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > +
> > > > >    #if IS_REACHABLE(CONFIG_FB)
> > > > >    	return remove_conflicting_framebuffers(a, name, primary);
> > > > >    #else
> > > > > @@ -43,7 +70,16 @@ static inline int
> > > > >    drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > >    						  const char *name)
> > > > >    {
> > > > > -	int ret = 0;
> > > > > +	resource_size_t base, size;
> > > > > +	int bar, ret = 0;
> > > > > +
> > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > +			continue;
> > > > > +		base = pci_resource_start(pdev, bar);
> > > > > +		size = pci_resource_len(pdev, bar);
> > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > +	}
> > > > >    	/*
> > > > >    	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > -- 
> > > > > 2.30.1
> > > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-15 12:57             ` Daniel Vetter
  (?)
@ 2021-04-15 19:12               ` Thomas Zimmermann
  -1 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 19:12 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied,
	emil.l.velikov, dri-devel, linux-doc, lgirdwood, virtualization,
	hdegoede, broonie, kraxel, sam


[-- Attachment #1.1: Type: text/plain, Size: 14275 bytes --]

Hi

Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>>>> Is it that easy? simepldrm's detach function has code to synchronize 
with
>>>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>>>> I'm all for it.
>>>
>>> Uh, I should have looked at the code instead of just asking silly
>>> questions :-)
>>>
>>> Now I'm even more scared, and also more convinced that we're recreating
>> a
>>> bad version of some of the core driver model concepts.
>>>
>>> I think the ideal option here would be if drm_aperture could unload
>>> (unbind really) the platform driver for us, through the driver model. 
Then
>>> there's only one place that keeps track whether the driver is unbound 
or
>>> not. I'm not sure whether this can be done fully generic on a struct
>>> device, or whether we need special code for each type. Since atm we only
>>> have simpledrm we can just specialize on platform_device and it's good
>>> enough.
>>
>> I meanwhile found that calling platform_device_unregister() is the right
>> thing to do. It is like a hot-unplug event. It's simple to implement and
>> removes the generic device as well. Any memory ranges for the generic device
>> are gone as well. Only the native driver's native device will remain. That's
>> better than the existing simplefb driver.
> 
> That sounds great.
> 
>> Which unregister function to call still driver-specific, so I kept the
>> callback.
> 
> Could we have the callback in core code, and you do something like
> drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> whatever, although tbh I'm not sure we ever get anything else than
> platform). That function can do a runtime check that drm_device->dev is
> actually a platform dev.

Somehow I knew you wouldn't like the current abstraction. :)

> 
> Another idea: Do the runtime casting in the core without anything? Atm we
> have platform that needs support, maybe pci device, so we could easily
> extend this and just let it do the right thing. Then no callback is
> needed. I.e.
> 
> 	if (is_platform_dev(drm_device->dev))
> 		platform_device_unregister(drm_device->dev);
> 	else
> 		WARN(1, "not yet implemented\n");
> 
> or something like that.

I don't like that. I spend time to remove the usb and pci device 
pointers from code and structs. I don't want to introduce a new 
hard-coded special case here.

> 
> I just find the callback to essentially unregister a device a bit
> redundant.

I'd like to go with your first idea. The callback would be internal and 
the public acquire function is specifically for firmware-based platform 
devices. That covers simple-framebuffer, VESA, EFI, and probably any 
other generic interface that fbdev supported in the last 20+ yrs. I 
don't think we'll ever need anything else.

Still, I'd like to have some abstraction between the internals of the 
aperture helpers and our actual use case. I'll update the patchset 
accordingly.

Best regards
Thomas

> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> I think best here would be to Cc: gregkh on this patch and the simpledrm
>>> ->detach implementatation, and ask for his feedback as driver model
>>> maintainer. Maybe if you could hack together the platform_device unbind
>>> path as proof of concept would be even better.
>>>
>>> Either way, this is really tricky.
>>> -Daniel
>>>
>>>>
>>>> Best regards
>>>> Thomas
>>>>
>>>>>
>>>>> Or maybe we should tie this more into the struct device mode and force an
>>>>> unload that way? That way devm cleanup would work as one expects, and
>>>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>>>
>>>>> Just feels a bit like we're reinventing half of the driver model here,
>>>>> badly.
>>>>>
>>>>>> + *	};
>>>>>> + *
>>>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct 
pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		resource_size_t start, len;
>>>>>> + *		struct drm_aperture *ap;
>>>>>> + *
>>>>>> + *		base = pci_resource_start(pdev, 0);
>>>>>> + *		size = pci_resource_len(pdev, 0);
>>>>>> + *
>>>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>>>> + *		if (IS_ERR(ap))
>>>>>> + *			return PTR_ERR(ap);
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static int probe(struct pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		struct drm_device *dev;
>>>>>> + *		int ret;
>>>>>> + *
>>>>>> + *		// ... Initialize the device...
>>>>>> + *		dev = devm_drm_dev_alloc();
>>>>>> + *		...
>>>>>> + *
>>>>>> + *		// ... and acquire ownership of the framebuffer.
>>>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>>>> + *		if (ret)
>>>>>> + *			return ret;
>>>>>> + *
>>>>>> + *		drm_dev_register();
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>>>> + * like an unplug event.
>>>>>> + *
>>>>>> + * .. code-block:: c
>>>>>> + *
>>>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>>>> + *				       resource_size_t base,
>>>>>> + *				       resource_size_t size)
>>>>>> + *	{
>>>>>> + *		// Signal unplug
>>>>>> + *		drm_dev_unplug(dev);
>>>>>> + *
>>>>>> + *		// Maybe do other clean-up operations
>>>>>> + *		...
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>>>> + *		.detach = detach_from_device,
>>>>>> + *	};
>>>>>> + */
>>>>>> +
>>>>>> +/**
>>>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>>>> + *
>>>>>> + * This structure has no public fields.
>>>>>> + */
>>>>>> +struct drm_aperture {
>>>>>> +	struct drm_device *dev;
>>>>>> +	resource_size_t base;
>>>>>> +	resource_size_t size;
>>>>>> +
>>>>>> +	const struct drm_aperture_funcs *funcs;
>>>>>> +
>>>>>> +	struct list_head lh;
>>>>>> +};
>>>>>> +
>>>>>> +static LIST_HEAD(drm_apertures);
>>>>>> +
>>>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>>>> +
>>>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>>>> +		    resource_size_t base2, resource_size_t end2)
>>>>>> +{
>>>>>> +	return (base1 < end2) && (end1 > base2);
>>>>>> +}
>>>>>> +
>>>>>> +static void devm_aperture_acquire_release(void *data)
>>>>>> +{
>>>>>> +	struct drm_aperture *ap = data;
>>>>>> +	bool detached = !ap->dev;
>>>>>> +
>>>>>> +	if (!detached)
>>>>>
>>>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>>>
>>>>>> +		mutex_lock(&drm_apertures_lock);
>>>>>
>>>>> and an
>>>>>
>>>>> 	else
>>>>> 		locdep_assert_held(&drm_apertures_lock);
>>>>>
>>>>> here to check that. I was scratching my head first quite a bit how you'd
>>>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>>>> came up with in my head). But needs comments.
>>>>>
>>>>>> +
>>>>>> +	list_del(&ap->lh);
>>>>>> +
>>>>>> +	if (!detached)
>>>>>> +		mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on 
behalf of a DRM driver.
>>>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>>>> + * @size:	the framebuffer size in bytes
>>>>>> + * @funcs:	callback functions
>>>>>> + *
>>>>>> + * Installs the given device as the new owner. The function fails 
if the
>>>>>> + * framebuffer range, or parts of it, is currently owned by
>>>>>> another
>> driver.
>>>>>> + * To evict current owners, callers should use
>>>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>>>> + * function. Acquired apertures are released automatically if the 
underlying
>>>>>> + * device goes away.
>>>>>> + *
>>>>>> + * Returns:
>>>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>>>> + * errno value otherwise.
>>>>>> + */
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs)
>>>>>> +{
>>>>>> +	size_t end = base + size;
>>>>>> +	struct list_head *pos;
>>>>>> +	struct drm_aperture *ap;
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each(pos, &drm_apertures) {
>>>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			return ERR_PTR(-EBUSY);
>>>>>> +	}
>>>>>> +
>>>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>>>> +	if (!ap)
>>>>>> +		return ERR_PTR(-ENOMEM);
>>>>>> +
>>>>>> +	ap->dev = dev;
>>>>>> +	ap->base = base;
>>>>>> +	ap->size = size;
>>>>>> +	ap->funcs = funcs;
>>>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>>>> +
>>>>>> +	list_add(&ap->lh, &drm_apertures);
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>>>> +	if (ret)
>>>>>> +		return ERR_PTR(ret);
>>>>>> +
>>>>>> +	return ap;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>>>> +
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>>>> +{
>>>>>> +	resource_size_t end = base + size;
>>>>>> +	struct list_head *pos, *n;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>>>> +		struct drm_aperture *ap =
>>>>>> +			container_of(pos, struct drm_aperture, lh);
>>>>>> +		struct drm_device *dev = ap->dev;
>>>>>> +
>>>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			continue;
>>>>>> +
>>>>>> +		ap->dev = NULL; /* detach from device */
>>>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>>>> +			continue;
>>>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>>>> +	}
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>>>
>>>>> Is this just exported because of the inline functions in the
>>>>> headers?
>> Imo
>>>>> better to make them proper functions (they're big after your patch&not
>>>>> perf critical, so not good candidates for inlining anyway).
>>>>>
>>>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>>>> index 13766efe9517..696cec75ef78 100644
>>>>>> --- a/include/drm/drm_aperture.h
>>>>>> +++ b/include/drm/drm_aperture.h
>>>>>> @@ -4,8 +4,30 @@
>>>>>>     #define _DRM_APERTURE_H_
>>>>>>     #include <linux/fb.h>
>>>>>> +#include <linux/pci.h>
>>>>>>     #include <linux/vgaarb.h>
>>>>>> +struct drm_aperture;
>>>>>> +struct drm_device;
>>>>>> +
>>>>>> +struct drm_aperture_funcs {
>>>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>>>> +};
>>>>>> +
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs);
>>>>>> +
>>>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>>>> +#else
>>>>>> +static inline void
>>>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t 
size)
>>>>>> +{
>>>>>> +}
>>>>>> +#endif
>>>>>> +
>>>>>>     /**
>>>>>>      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>>>      * @a: memory range, users of which are to be removed
>>>>>> @@ -20,6 +42,11 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>>>     					      const char *name, bool primary)
>>>>>>     {
>>>>>> +	int i;
>>>>>> +
>>>>>> +	for (i = 0; i < a->count; ++i)
>>>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>>>> +
>>>>>>     #if IS_REACHABLE(CONFIG_FB)
>>>>>>     	return remove_conflicting_framebuffers(a, name, primary);
>>>>>>     #else
>>>>>> @@ -43,7 +70,16 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>>>     						  const char *name)
>>>>>>     {
>>>>>> -	int ret = 0;
>>>>>> +	resource_size_t base, size;
>>>>>> +	int bar, ret = 0;
>>>>>> +
>>>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>>>> +			continue;
>>>>>> +		base = pci_resource_start(pdev, bar);
>>>>>> +		size = pci_resource_len(pdev, bar);
>>>>>> +		drm_aperture_detach_drivers(base, size);
>>>>>> +	}
>>>>>>     	/*
>>>>>>     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>>>> -- 
>>>>>> 2.30.1
>>>>>>
>>>>>
>>>>
>>>> -- 
>>>> Thomas Zimmermann
>>>> Graphics Driver Developer
>>>> SUSE Software Solutions Germany GmbH
>>>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>>>> (HRB 36809, AG Nürnberg)
>>>> Geschäftsführer: Felix Imendörffer
>>>>
>>>
>>>
>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15 19:12               ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 19:12 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 14275 bytes --]

Hi

Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>>>> Is it that easy? simepldrm's detach function has code to synchronize 
with
>>>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>>>> I'm all for it.
>>>
>>> Uh, I should have looked at the code instead of just asking silly
>>> questions :-)
>>>
>>> Now I'm even more scared, and also more convinced that we're recreating
>> a
>>> bad version of some of the core driver model concepts.
>>>
>>> I think the ideal option here would be if drm_aperture could unload
>>> (unbind really) the platform driver for us, through the driver model. 
Then
>>> there's only one place that keeps track whether the driver is unbound 
or
>>> not. I'm not sure whether this can be done fully generic on a struct
>>> device, or whether we need special code for each type. Since atm we only
>>> have simpledrm we can just specialize on platform_device and it's good
>>> enough.
>>
>> I meanwhile found that calling platform_device_unregister() is the right
>> thing to do. It is like a hot-unplug event. It's simple to implement and
>> removes the generic device as well. Any memory ranges for the generic device
>> are gone as well. Only the native driver's native device will remain. That's
>> better than the existing simplefb driver.
> 
> That sounds great.
> 
>> Which unregister function to call still driver-specific, so I kept the
>> callback.
> 
> Could we have the callback in core code, and you do something like
> drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> whatever, although tbh I'm not sure we ever get anything else than
> platform). That function can do a runtime check that drm_device->dev is
> actually a platform dev.

Somehow I knew you wouldn't like the current abstraction. :)

> 
> Another idea: Do the runtime casting in the core without anything? Atm we
> have platform that needs support, maybe pci device, so we could easily
> extend this and just let it do the right thing. Then no callback is
> needed. I.e.
> 
> 	if (is_platform_dev(drm_device->dev))
> 		platform_device_unregister(drm_device->dev);
> 	else
> 		WARN(1, "not yet implemented\n");
> 
> or something like that.

I don't like that. I spend time to remove the usb and pci device 
pointers from code and structs. I don't want to introduce a new 
hard-coded special case here.

> 
> I just find the callback to essentially unregister a device a bit
> redundant.

I'd like to go with your first idea. The callback would be internal and 
the public acquire function is specifically for firmware-based platform 
devices. That covers simple-framebuffer, VESA, EFI, and probably any 
other generic interface that fbdev supported in the last 20+ yrs. I 
don't think we'll ever need anything else.

Still, I'd like to have some abstraction between the internals of the 
aperture helpers and our actual use case. I'll update the patchset 
accordingly.

Best regards
Thomas

> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> I think best here would be to Cc: gregkh on this patch and the simpledrm
>>> ->detach implementatation, and ask for his feedback as driver model
>>> maintainer. Maybe if you could hack together the platform_device unbind
>>> path as proof of concept would be even better.
>>>
>>> Either way, this is really tricky.
>>> -Daniel
>>>
>>>>
>>>> Best regards
>>>> Thomas
>>>>
>>>>>
>>>>> Or maybe we should tie this more into the struct device mode and force an
>>>>> unload that way? That way devm cleanup would work as one expects, and
>>>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>>>
>>>>> Just feels a bit like we're reinventing half of the driver model here,
>>>>> badly.
>>>>>
>>>>>> + *	};
>>>>>> + *
>>>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct 
pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		resource_size_t start, len;
>>>>>> + *		struct drm_aperture *ap;
>>>>>> + *
>>>>>> + *		base = pci_resource_start(pdev, 0);
>>>>>> + *		size = pci_resource_len(pdev, 0);
>>>>>> + *
>>>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>>>> + *		if (IS_ERR(ap))
>>>>>> + *			return PTR_ERR(ap);
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static int probe(struct pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		struct drm_device *dev;
>>>>>> + *		int ret;
>>>>>> + *
>>>>>> + *		// ... Initialize the device...
>>>>>> + *		dev = devm_drm_dev_alloc();
>>>>>> + *		...
>>>>>> + *
>>>>>> + *		// ... and acquire ownership of the framebuffer.
>>>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>>>> + *		if (ret)
>>>>>> + *			return ret;
>>>>>> + *
>>>>>> + *		drm_dev_register();
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>>>> + * like an unplug event.
>>>>>> + *
>>>>>> + * .. code-block:: c
>>>>>> + *
>>>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>>>> + *				       resource_size_t base,
>>>>>> + *				       resource_size_t size)
>>>>>> + *	{
>>>>>> + *		// Signal unplug
>>>>>> + *		drm_dev_unplug(dev);
>>>>>> + *
>>>>>> + *		// Maybe do other clean-up operations
>>>>>> + *		...
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>>>> + *		.detach = detach_from_device,
>>>>>> + *	};
>>>>>> + */
>>>>>> +
>>>>>> +/**
>>>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>>>> + *
>>>>>> + * This structure has no public fields.
>>>>>> + */
>>>>>> +struct drm_aperture {
>>>>>> +	struct drm_device *dev;
>>>>>> +	resource_size_t base;
>>>>>> +	resource_size_t size;
>>>>>> +
>>>>>> +	const struct drm_aperture_funcs *funcs;
>>>>>> +
>>>>>> +	struct list_head lh;
>>>>>> +};
>>>>>> +
>>>>>> +static LIST_HEAD(drm_apertures);
>>>>>> +
>>>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>>>> +
>>>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>>>> +		    resource_size_t base2, resource_size_t end2)
>>>>>> +{
>>>>>> +	return (base1 < end2) && (end1 > base2);
>>>>>> +}
>>>>>> +
>>>>>> +static void devm_aperture_acquire_release(void *data)
>>>>>> +{
>>>>>> +	struct drm_aperture *ap = data;
>>>>>> +	bool detached = !ap->dev;
>>>>>> +
>>>>>> +	if (!detached)
>>>>>
>>>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>>>
>>>>>> +		mutex_lock(&drm_apertures_lock);
>>>>>
>>>>> and an
>>>>>
>>>>> 	else
>>>>> 		locdep_assert_held(&drm_apertures_lock);
>>>>>
>>>>> here to check that. I was scratching my head first quite a bit how you'd
>>>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>>>> came up with in my head). But needs comments.
>>>>>
>>>>>> +
>>>>>> +	list_del(&ap->lh);
>>>>>> +
>>>>>> +	if (!detached)
>>>>>> +		mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on 
behalf of a DRM driver.
>>>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>>>> + * @size:	the framebuffer size in bytes
>>>>>> + * @funcs:	callback functions
>>>>>> + *
>>>>>> + * Installs the given device as the new owner. The function fails 
if the
>>>>>> + * framebuffer range, or parts of it, is currently owned by
>>>>>> another
>> driver.
>>>>>> + * To evict current owners, callers should use
>>>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>>>> + * function. Acquired apertures are released automatically if the 
underlying
>>>>>> + * device goes away.
>>>>>> + *
>>>>>> + * Returns:
>>>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>>>> + * errno value otherwise.
>>>>>> + */
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs)
>>>>>> +{
>>>>>> +	size_t end = base + size;
>>>>>> +	struct list_head *pos;
>>>>>> +	struct drm_aperture *ap;
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each(pos, &drm_apertures) {
>>>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			return ERR_PTR(-EBUSY);
>>>>>> +	}
>>>>>> +
>>>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>>>> +	if (!ap)
>>>>>> +		return ERR_PTR(-ENOMEM);
>>>>>> +
>>>>>> +	ap->dev = dev;
>>>>>> +	ap->base = base;
>>>>>> +	ap->size = size;
>>>>>> +	ap->funcs = funcs;
>>>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>>>> +
>>>>>> +	list_add(&ap->lh, &drm_apertures);
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>>>> +	if (ret)
>>>>>> +		return ERR_PTR(ret);
>>>>>> +
>>>>>> +	return ap;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>>>> +
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>>>> +{
>>>>>> +	resource_size_t end = base + size;
>>>>>> +	struct list_head *pos, *n;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>>>> +		struct drm_aperture *ap =
>>>>>> +			container_of(pos, struct drm_aperture, lh);
>>>>>> +		struct drm_device *dev = ap->dev;
>>>>>> +
>>>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			continue;
>>>>>> +
>>>>>> +		ap->dev = NULL; /* detach from device */
>>>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>>>> +			continue;
>>>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>>>> +	}
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>>>
>>>>> Is this just exported because of the inline functions in the
>>>>> headers?
>> Imo
>>>>> better to make them proper functions (they're big after your patch&not
>>>>> perf critical, so not good candidates for inlining anyway).
>>>>>
>>>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>>>> index 13766efe9517..696cec75ef78 100644
>>>>>> --- a/include/drm/drm_aperture.h
>>>>>> +++ b/include/drm/drm_aperture.h
>>>>>> @@ -4,8 +4,30 @@
>>>>>>     #define _DRM_APERTURE_H_
>>>>>>     #include <linux/fb.h>
>>>>>> +#include <linux/pci.h>
>>>>>>     #include <linux/vgaarb.h>
>>>>>> +struct drm_aperture;
>>>>>> +struct drm_device;
>>>>>> +
>>>>>> +struct drm_aperture_funcs {
>>>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>>>> +};
>>>>>> +
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs);
>>>>>> +
>>>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>>>> +#else
>>>>>> +static inline void
>>>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t 
size)
>>>>>> +{
>>>>>> +}
>>>>>> +#endif
>>>>>> +
>>>>>>     /**
>>>>>>      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>>>      * @a: memory range, users of which are to be removed
>>>>>> @@ -20,6 +42,11 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>>>     					      const char *name, bool primary)
>>>>>>     {
>>>>>> +	int i;
>>>>>> +
>>>>>> +	for (i = 0; i < a->count; ++i)
>>>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>>>> +
>>>>>>     #if IS_REACHABLE(CONFIG_FB)
>>>>>>     	return remove_conflicting_framebuffers(a, name, primary);
>>>>>>     #else
>>>>>> @@ -43,7 +70,16 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>>>     						  const char *name)
>>>>>>     {
>>>>>> -	int ret = 0;
>>>>>> +	resource_size_t base, size;
>>>>>> +	int bar, ret = 0;
>>>>>> +
>>>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>>>> +			continue;
>>>>>> +		base = pci_resource_start(pdev, bar);
>>>>>> +		size = pci_resource_len(pdev, bar);
>>>>>> +		drm_aperture_detach_drivers(base, size);
>>>>>> +	}
>>>>>>     	/*
>>>>>>     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>>>> -- 
>>>>>> 2.30.1
>>>>>>
>>>>>
>>>>
>>>> -- 
>>>> Thomas Zimmermann
>>>> Graphics Driver Developer
>>>> SUSE Software Solutions Germany GmbH
>>>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>>>> (HRB 36809, AG Nürnberg)
>>>> Geschäftsführer: Felix Imendörffer
>>>>
>>>
>>>
>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 183 bytes --]

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-15 19:12               ` Thomas Zimmermann
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Zimmermann @ 2021-04-15 19:12 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, kraxel, sam


[-- Attachment #1.1.1: Type: text/plain, Size: 14275 bytes --]

Hi

Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 09.04.21 um 11:22 schrieb Daniel Vetter:
>>>> Is it that easy? simepldrm's detach function has code to synchronize 
with
>>>> concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
>>>> I'm all for it.
>>>
>>> Uh, I should have looked at the code instead of just asking silly
>>> questions :-)
>>>
>>> Now I'm even more scared, and also more convinced that we're recreating
>> a
>>> bad version of some of the core driver model concepts.
>>>
>>> I think the ideal option here would be if drm_aperture could unload
>>> (unbind really) the platform driver for us, through the driver model. 
Then
>>> there's only one place that keeps track whether the driver is unbound 
or
>>> not. I'm not sure whether this can be done fully generic on a struct
>>> device, or whether we need special code for each type. Since atm we only
>>> have simpledrm we can just specialize on platform_device and it's good
>>> enough.
>>
>> I meanwhile found that calling platform_device_unregister() is the right
>> thing to do. It is like a hot-unplug event. It's simple to implement and
>> removes the generic device as well. Any memory ranges for the generic device
>> are gone as well. Only the native driver's native device will remain. That's
>> better than the existing simplefb driver.
> 
> That sounds great.
> 
>> Which unregister function to call still driver-specific, so I kept the
>> callback.
> 
> Could we have the callback in core code, and you do something like
> drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> whatever, although tbh I'm not sure we ever get anything else than
> platform). That function can do a runtime check that drm_device->dev is
> actually a platform dev.

Somehow I knew you wouldn't like the current abstraction. :)

> 
> Another idea: Do the runtime casting in the core without anything? Atm we
> have platform that needs support, maybe pci device, so we could easily
> extend this and just let it do the right thing. Then no callback is
> needed. I.e.
> 
> 	if (is_platform_dev(drm_device->dev))
> 		platform_device_unregister(drm_device->dev);
> 	else
> 		WARN(1, "not yet implemented\n");
> 
> or something like that.

I don't like that. I spend time to remove the usb and pci device 
pointers from code and structs. I don't want to introduce a new 
hard-coded special case here.

> 
> I just find the callback to essentially unregister a device a bit
> redundant.

I'd like to go with your first idea. The callback would be internal and 
the public acquire function is specifically for firmware-based platform 
devices. That covers simple-framebuffer, VESA, EFI, and probably any 
other generic interface that fbdev supported in the last 20+ yrs. I 
don't think we'll ever need anything else.

Still, I'd like to have some abstraction between the internals of the 
aperture helpers and our actual use case. I'll update the patchset 
accordingly.

Best regards
Thomas

> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>>
>>> I think best here would be to Cc: gregkh on this patch and the simpledrm
>>> ->detach implementatation, and ask for his feedback as driver model
>>> maintainer. Maybe if you could hack together the platform_device unbind
>>> path as proof of concept would be even better.
>>>
>>> Either way, this is really tricky.
>>> -Daniel
>>>
>>>>
>>>> Best regards
>>>> Thomas
>>>>
>>>>>
>>>>> Or maybe we should tie this more into the struct device mode and force an
>>>>> unload that way? That way devm cleanup would work as one expects, and
>>>>> avoid the need for anything specific (hopefully) in this detach callback.
>>>>>
>>>>> Just feels a bit like we're reinventing half of the driver model here,
>>>>> badly.
>>>>>
>>>>>> + *	};
>>>>>> + *
>>>>>> + *	static int acquire_framebuffers(struct drm_device *dev, struct 
pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		resource_size_t start, len;
>>>>>> + *		struct drm_aperture *ap;
>>>>>> + *
>>>>>> + *		base = pci_resource_start(pdev, 0);
>>>>>> + *		size = pci_resource_len(pdev, 0);
>>>>>> + *
>>>>>> + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
>>>>>> + *		if (IS_ERR(ap))
>>>>>> + *			return PTR_ERR(ap);
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static int probe(struct pci_dev *pdev)
>>>>>> + *	{
>>>>>> + *		struct drm_device *dev;
>>>>>> + *		int ret;
>>>>>> + *
>>>>>> + *		// ... Initialize the device...
>>>>>> + *		dev = devm_drm_dev_alloc();
>>>>>> + *		...
>>>>>> + *
>>>>>> + *		// ... and acquire ownership of the framebuffer.
>>>>>> + *		ret = acquire_framebuffers(dev, pdev);
>>>>>> + *		if (ret)
>>>>>> + *			return ret;
>>>>>> + *
>>>>>> + *		drm_dev_register();
>>>>>> + *
>>>>>> + *		return 0;
>>>>>> + *	}
>>>>>> + *
>>>>>> + * The generic driver is now subject to forced removal by other drivers. This
>>>>>> + * is when the detach function in struct &drm_aperture_funcs comes into play.
>>>>>> + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
>>>>>> + * for the registered framebuffer range, the DRM core calls struct
>>>>>> + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
>>>>>> + * may not access the device's registers, framebuffer memory, ROM, etc after
>>>>>> + * detach returned. If the driver supports hotplugging, detach can be treated
>>>>>> + * like an unplug event.
>>>>>> + *
>>>>>> + * .. code-block:: c
>>>>>> + *
>>>>>> + *	static void detach_from_device(struct drm_device *dev,
>>>>>> + *				       resource_size_t base,
>>>>>> + *				       resource_size_t size)
>>>>>> + *	{
>>>>>> + *		// Signal unplug
>>>>>> + *		drm_dev_unplug(dev);
>>>>>> + *
>>>>>> + *		// Maybe do other clean-up operations
>>>>>> + *		...
>>>>>> + *	}
>>>>>> + *
>>>>>> + *	static struct drm_aperture_funcs ap_funcs = {
>>>>>> + *		.detach = detach_from_device,
>>>>>> + *	};
>>>>>> + */
>>>>>> +
>>>>>> +/**
>>>>>> + * struct drm_aperture - Represents a DRM framebuffer aperture
>>>>>> + *
>>>>>> + * This structure has no public fields.
>>>>>> + */
>>>>>> +struct drm_aperture {
>>>>>> +	struct drm_device *dev;
>>>>>> +	resource_size_t base;
>>>>>> +	resource_size_t size;
>>>>>> +
>>>>>> +	const struct drm_aperture_funcs *funcs;
>>>>>> +
>>>>>> +	struct list_head lh;
>>>>>> +};
>>>>>> +
>>>>>> +static LIST_HEAD(drm_apertures);
>>>>>> +
>>>>>> +static DEFINE_MUTEX(drm_apertures_lock);
>>>>>> +
>>>>>> +static bool overlap(resource_size_t base1, resource_size_t end1,
>>>>>> +		    resource_size_t base2, resource_size_t end2)
>>>>>> +{
>>>>>> +	return (base1 < end2) && (end1 > base2);
>>>>>> +}
>>>>>> +
>>>>>> +static void devm_aperture_acquire_release(void *data)
>>>>>> +{
>>>>>> +	struct drm_aperture *ap = data;
>>>>>> +	bool detached = !ap->dev;
>>>>>> +
>>>>>> +	if (!detached)
>>>>>
>>>>> Uh this needs a comment that if ap->dev is NULL then we're called from
>>>>> drm_aperture_detach_drivers() and hence the lock is already held.
>>>>>
>>>>>> +		mutex_lock(&drm_apertures_lock);
>>>>>
>>>>> and an
>>>>>
>>>>> 	else
>>>>> 		locdep_assert_held(&drm_apertures_lock);
>>>>>
>>>>> here to check that. I was scratching my head first quite a bit how you'd
>>>>> solve the deadlock, this is a neat solution (much simpler than anything I
>>>>> came up with in my head). But needs comments.
>>>>>
>>>>>> +
>>>>>> +	list_del(&ap->lh);
>>>>>> +
>>>>>> +	if (!detached)
>>>>>> +		mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * devm_aperture_acquire - Acquires ownership of a framebuffer on 
behalf of a DRM driver.
>>>>>> + * @dev:	the DRM device to own the framebuffer memory
>>>>>> + * @base:	the framebuffer's byte offset in physical memory
>>>>>> + * @size:	the framebuffer size in bytes
>>>>>> + * @funcs:	callback functions
>>>>>> + *
>>>>>> + * Installs the given device as the new owner. The function fails 
if the
>>>>>> + * framebuffer range, or parts of it, is currently owned by
>>>>>> another
>> driver.
>>>>>> + * To evict current owners, callers should use
>>>>>> + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
>>>>>> + * function. Acquired apertures are released automatically if the 
underlying
>>>>>> + * device goes away.
>>>>>> + *
>>>>>> + * Returns:
>>>>>> + * An instance of struct &drm_aperture on success, or a pointer-encoded
>>>>>> + * errno value otherwise.
>>>>>> + */
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs)
>>>>>> +{
>>>>>> +	size_t end = base + size;
>>>>>> +	struct list_head *pos;
>>>>>> +	struct drm_aperture *ap;
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each(pos, &drm_apertures) {
>>>>>> +		ap = container_of(pos, struct drm_aperture, lh);
>>>>>> +		if (overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			return ERR_PTR(-EBUSY);
>>>>>> +	}
>>>>>> +
>>>>>> +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
>>>>>> +	if (!ap)
>>>>>> +		return ERR_PTR(-ENOMEM);
>>>>>> +
>>>>>> +	ap->dev = dev;
>>>>>> +	ap->base = base;
>>>>>> +	ap->size = size;
>>>>>> +	ap->funcs = funcs;
>>>>>> +	INIT_LIST_HEAD(&ap->lh);
>>>>>> +
>>>>>> +	list_add(&ap->lh, &drm_apertures);
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
>>>>>> +	if (ret)
>>>>>> +		return ERR_PTR(ret);
>>>>>> +
>>>>>> +	return ap;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(devm_aperture_acquire);
>>>>>> +
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
>>>>>> +{
>>>>>> +	resource_size_t end = base + size;
>>>>>> +	struct list_head *pos, *n;
>>>>>> +
>>>>>> +	mutex_lock(&drm_apertures_lock);
>>>>>> +
>>>>>> +	list_for_each_safe(pos, n, &drm_apertures) {
>>>>>> +		struct drm_aperture *ap =
>>>>>> +			container_of(pos, struct drm_aperture, lh);
>>>>>> +		struct drm_device *dev = ap->dev;
>>>>>> +
>>>>>> +		if (!overlap(base, end, ap->base, ap->base + ap->size))
>>>>>> +			continue;
>>>>>> +
>>>>>> +		ap->dev = NULL; /* detach from device */
>>>>>> +		if (drm_WARN_ON(dev, !ap->funcs->detach))
>>>>>> +			continue;
>>>>>> +		ap->funcs->detach(dev, ap->base, ap->size);
>>>>>> +	}
>>>>>> +
>>>>>> +	mutex_unlock(&drm_apertures_lock);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(drm_aperture_detach_drivers);
>>>>>
>>>>> Is this just exported because of the inline functions in the
>>>>> headers?
>> Imo
>>>>> better to make them proper functions (they're big after your patch&not
>>>>> perf critical, so not good candidates for inlining anyway).
>>>>>
>>>>>> diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
>>>>>> index 13766efe9517..696cec75ef78 100644
>>>>>> --- a/include/drm/drm_aperture.h
>>>>>> +++ b/include/drm/drm_aperture.h
>>>>>> @@ -4,8 +4,30 @@
>>>>>>     #define _DRM_APERTURE_H_
>>>>>>     #include <linux/fb.h>
>>>>>> +#include <linux/pci.h>
>>>>>>     #include <linux/vgaarb.h>
>>>>>> +struct drm_aperture;
>>>>>> +struct drm_device;
>>>>>> +
>>>>>> +struct drm_aperture_funcs {
>>>>>> +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
>>>>>> +};
>>>>>> +
>>>>>> +struct drm_aperture *
>>>>>> +devm_aperture_acquire(struct drm_device *dev,
>>>>>> +		      resource_size_t base, resource_size_t size,
>>>>>> +		      const struct drm_aperture_funcs *funcs);
>>>>>> +
>>>>>> +#if defined(CONFIG_DRM_APERTURE)
>>>>>> +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
>>>>>> +#else
>>>>>> +static inline void
>>>>>> +drm_aperture_detach_drivers(resource_size_t base, resource_size_t 
size)
>>>>>> +{
>>>>>> +}
>>>>>> +#endif
>>>>>> +
>>>>>>     /**
>>>>>>      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
>>>>>>      * @a: memory range, users of which are to be removed
>>>>>> @@ -20,6 +42,11 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
>>>>>>     					      const char *name, bool primary)
>>>>>>     {
>>>>>> +	int i;
>>>>>> +
>>>>>> +	for (i = 0; i < a->count; ++i)
>>>>>> +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
>>>>>> +
>>>>>>     #if IS_REACHABLE(CONFIG_FB)
>>>>>>     	return remove_conflicting_framebuffers(a, name, primary);
>>>>>>     #else
>>>>>> @@ -43,7 +70,16 @@ static inline int
>>>>>>     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
>>>>>>     						  const char *name)
>>>>>>     {
>>>>>> -	int ret = 0;
>>>>>> +	resource_size_t base, size;
>>>>>> +	int bar, ret = 0;
>>>>>> +
>>>>>> +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>>>> +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
>>>>>> +			continue;
>>>>>> +		base = pci_resource_start(pdev, bar);
>>>>>> +		size = pci_resource_len(pdev, bar);
>>>>>> +		drm_aperture_detach_drivers(base, size);
>>>>>> +	}
>>>>>>     	/*
>>>>>>     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
>>>>>> -- 
>>>>>> 2.30.1
>>>>>>
>>>>>
>>>>
>>>> -- 
>>>> Thomas Zimmermann
>>>> Graphics Driver Developer
>>>> SUSE Software Solutions Germany GmbH
>>>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>>>> (HRB 36809, AG Nürnberg)
>>>> Geschäftsführer: Felix Imendörffer
>>>>
>>>
>>>
>>>
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
  2021-04-15 19:12               ` Thomas Zimmermann
  (?)
@ 2021-04-16  8:42                 ` Daniel Vetter
  -1 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-16  8:42 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Daniel Vetter, bluescreen_avenger, geert+renesas, corbet,
	airlied, emil.l.velikov, dri-devel, linux-doc, lgirdwood,
	virtualization, hdegoede, broonie, kraxel, sam

On Thu, Apr 15, 2021 at 09:12:14PM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> > On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> > > Hi
> > > 
> > > Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > > > Is it that easy? simepldrm's detach function has code to
> > > > > synchronize
> with
> > > > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > > > I'm all for it.
> > > > 
> > > > Uh, I should have looked at the code instead of just asking silly
> > > > questions :-)
> > > > 
> > > > Now I'm even more scared, and also more convinced that we're recreating
> > > a
> > > > bad version of some of the core driver model concepts.
> > > > 
> > > > I think the ideal option here would be if drm_aperture could unload
> > > > (unbind really) the platform driver for us, through the driver
> > > > model.
> Then
> > > > there's only one place that keeps track whether the driver is
> > > > unbound
> or
> > > > not. I'm not sure whether this can be done fully generic on a struct
> > > > device, or whether we need special code for each type. Since atm we only
> > > > have simpledrm we can just specialize on platform_device and it's good
> > > > enough.
> > > 
> > > I meanwhile found that calling platform_device_unregister() is the right
> > > thing to do. It is like a hot-unplug event. It's simple to implement and
> > > removes the generic device as well. Any memory ranges for the generic device
> > > are gone as well. Only the native driver's native device will remain. That's
> > > better than the existing simplefb driver.
> > 
> > That sounds great.
> > 
> > > Which unregister function to call still driver-specific, so I kept the
> > > callback.
> > 
> > Could we have the callback in core code, and you do something like
> > drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> > whatever, although tbh I'm not sure we ever get anything else than
> > platform). That function can do a runtime check that drm_device->dev is
> > actually a platform dev.
> 
> Somehow I knew you wouldn't like the current abstraction. :)
> 
> > 
> > Another idea: Do the runtime casting in the core without anything? Atm we
> > have platform that needs support, maybe pci device, so we could easily
> > extend this and just let it do the right thing. Then no callback is
> > needed. I.e.
> > 
> > 	if (is_platform_dev(drm_device->dev))
> > 		platform_device_unregister(drm_device->dev);
> > 	else
> > 		WARN(1, "not yet implemented\n");
> > 
> > or something like that.
> 
> I don't like that. I spend time to remove the usb and pci device pointers
> from code and structs. I don't want to introduce a new hard-coded special
> case here.
> 
> > 
> > I just find the callback to essentially unregister a device a bit
> > redundant.
> 
> I'd like to go with your first idea. The callback would be internal and the
> public acquire function is specifically for firmware-based platform devices.
> That covers simple-framebuffer, VESA, EFI, and probably any other generic
> interface that fbdev supported in the last 20+ yrs. I don't think we'll ever
> need anything else.
> 
> Still, I'd like to have some abstraction between the internals of the
> aperture helpers and our actual use case. I'll update the patchset
> accordingly.

Makes sense and I'm happy with that pick of color choice. That keeps the
noise out of drivers, and also keeps the concepts clean internally.
-Daniel


> 
> Best regards
> Thomas
> 
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > > > ->detach implementatation, and ask for his feedback as driver model
> > > > maintainer. Maybe if you could hack together the platform_device unbind
> > > > path as proof of concept would be even better.
> > > > 
> > > > Either way, this is really tricky.
> > > > -Daniel
> > > > 
> > > > > 
> > > > > Best regards
> > > > > Thomas
> > > > > 
> > > > > > 
> > > > > > Or maybe we should tie this more into the struct device mode and force an
> > > > > > unload that way? That way devm cleanup would work as one expects, and
> > > > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > > > 
> > > > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > > > badly.
> > > > > > 
> > > > > > > + *	};
> > > > > > > + *
> > > > > > > + *	static int acquire_framebuffers(struct
> > > > > > > drm_device *dev, struct
> pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		resource_size_t start, len;
> > > > > > > + *		struct drm_aperture *ap;
> > > > > > > + *
> > > > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > > > + *
> > > > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > > > + *		if (IS_ERR(ap))
> > > > > > > + *			return PTR_ERR(ap);
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		struct drm_device *dev;
> > > > > > > + *		int ret;
> > > > > > > + *
> > > > > > > + *		// ... Initialize the device...
> > > > > > > + *		dev = devm_drm_dev_alloc();
> > > > > > > + *		...
> > > > > > > + *
> > > > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > > > + *		if (ret)
> > > > > > > + *			return ret;
> > > > > > > + *
> > > > > > > + *		drm_dev_register();
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > > > + * like an unplug event.
> > > > > > > + *
> > > > > > > + * .. code-block:: c
> > > > > > > + *
> > > > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > > > + *				       resource_size_t base,
> > > > > > > + *				       resource_size_t size)
> > > > > > > + *	{
> > > > > > > + *		// Signal unplug
> > > > > > > + *		drm_dev_unplug(dev);
> > > > > > > + *
> > > > > > > + *		// Maybe do other clean-up operations
> > > > > > > + *		...
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > > > + *		.detach = detach_from_device,
> > > > > > > + *	};
> > > > > > > + */
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > > > + *
> > > > > > > + * This structure has no public fields.
> > > > > > > + */
> > > > > > > +struct drm_aperture {
> > > > > > > +	struct drm_device *dev;
> > > > > > > +	resource_size_t base;
> > > > > > > +	resource_size_t size;
> > > > > > > +
> > > > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > > > +
> > > > > > > +	struct list_head lh;
> > > > > > > +};
> > > > > > > +
> > > > > > > +static LIST_HEAD(drm_apertures);
> > > > > > > +
> > > > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > > > +
> > > > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > > > +{
> > > > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > > > +{
> > > > > > > +	struct drm_aperture *ap = data;
> > > > > > > +	bool detached = !ap->dev;
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > 
> > > > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > > > 
> > > > > > > +		mutex_lock(&drm_apertures_lock);
> > > > > > 
> > > > > > and an
> > > > > > 
> > > > > > 	else
> > > > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > > > 
> > > > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > > > came up with in my head). But needs comments.
> > > > > > 
> > > > > > > +
> > > > > > > +	list_del(&ap->lh);
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * devm_aperture_acquire - Acquires ownership of a
> > > > > > > framebuffer on
> behalf of a DRM driver.
> > > > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > > > + * @size:	the framebuffer size in bytes
> > > > > > > + * @funcs:	callback functions
> > > > > > > + *
> > > > > > > + * Installs the given device as the new owner. The
> > > > > > > function fails
> if the
> > > > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > > > another
> > > driver.
> > > > > > > + * To evict current owners, callers should use
> > > > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > > > + * function. Acquired apertures are released
> > > > > > > automatically if the
> underlying
> > > > > > > + * device goes away.
> > > > > > > + *
> > > > > > > + * Returns:
> > > > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > > > + * errno value otherwise.
> > > > > > > + */
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > > > +{
> > > > > > > +	size_t end = base + size;
> > > > > > > +	struct list_head *pos;
> > > > > > > +	struct drm_aperture *ap;
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			return ERR_PTR(-EBUSY);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > > > +	if (!ap)
> > > > > > > +		return ERR_PTR(-ENOMEM);
> > > > > > > +
> > > > > > > +	ap->dev = dev;
> > > > > > > +	ap->base = base;
> > > > > > > +	ap->size = size;
> > > > > > > +	ap->funcs = funcs;
> > > > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > > > +
> > > > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > > > +	if (ret)
> > > > > > > +		return ERR_PTR(ret);
> > > > > > > +
> > > > > > > +	return ap;
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > > > +
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > > > +{
> > > > > > > +	resource_size_t end = base + size;
> > > > > > > +	struct list_head *pos, *n;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > > > +		struct drm_aperture *ap =
> > > > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > > > +		struct drm_device *dev = ap->dev;
> > > > > > > +
> > > > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			continue;
> > > > > > > +
> > > > > > > +		ap->dev = NULL; /* detach from device */
> > > > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > > > +			continue;
> > > > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > > > 
> > > > > > Is this just exported because of the inline functions in the
> > > > > > headers?
> > > Imo
> > > > > > better to make them proper functions (they're big after your patch&not
> > > > > > perf critical, so not good candidates for inlining anyway).
> > > > > > 
> > > > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > > > index 13766efe9517..696cec75ef78 100644
> > > > > > > --- a/include/drm/drm_aperture.h
> > > > > > > +++ b/include/drm/drm_aperture.h
> > > > > > > @@ -4,8 +4,30 @@
> > > > > > >     #define _DRM_APERTURE_H_
> > > > > > >     #include <linux/fb.h>
> > > > > > > +#include <linux/pci.h>
> > > > > > >     #include <linux/vgaarb.h>
> > > > > > > +struct drm_aperture;
> > > > > > > +struct drm_device;
> > > > > > > +
> > > > > > > +struct drm_aperture_funcs {
> > > > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > > > +};
> > > > > > > +
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > > > +
> > > > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > > > +#else
> > > > > > > +static inline void
> > > > > > > +drm_aperture_detach_drivers(resource_size_t base,
> > > > > > > resource_size_t
> size)
> > > > > > > +{
> > > > > > > +}
> > > > > > > +#endif
> > > > > > > +
> > > > > > >     /**
> > > > > > >      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > > > >      * @a: memory range, users of which are to be removed
> > > > > > > @@ -20,6 +42,11 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > > > >     					      const char *name, bool primary)
> > > > > > >     {
> > > > > > > +	int i;
> > > > > > > +
> > > > > > > +	for (i = 0; i < a->count; ++i)
> > > > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > > > +
> > > > > > >     #if IS_REACHABLE(CONFIG_FB)
> > > > > > >     	return remove_conflicting_framebuffers(a, name, primary);
> > > > > > >     #else
> > > > > > > @@ -43,7 +70,16 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > > > >     						  const char *name)
> > > > > > >     {
> > > > > > > -	int ret = 0;
> > > > > > > +	resource_size_t base, size;
> > > > > > > +	int bar, ret = 0;
> > > > > > > +
> > > > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > > > +			continue;
> > > > > > > +		base = pci_resource_start(pdev, bar);
> > > > > > > +		size = pci_resource_len(pdev, bar);
> > > > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > > > +	}
> > > > > > >     	/*
> > > > > > >     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > > > -- 
> > > > > > > 2.30.1
> > > > > > > 
> > > > > > 
> > > > > 
> > > > > -- 
> > > > > Thomas Zimmermann
> > > > > Graphics Driver Developer
> > > > > SUSE Software Solutions Germany GmbH
> > > > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > > > (HRB 36809, AG Nürnberg)
> > > > > Geschäftsführer: Felix Imendörffer
> > > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-16  8:42                 ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-16  8:42 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, Daniel Vetter, sam

On Thu, Apr 15, 2021 at 09:12:14PM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> > On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> > > Hi
> > > 
> > > Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > > > Is it that easy? simepldrm's detach function has code to
> > > > > synchronize
> with
> > > > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > > > I'm all for it.
> > > > 
> > > > Uh, I should have looked at the code instead of just asking silly
> > > > questions :-)
> > > > 
> > > > Now I'm even more scared, and also more convinced that we're recreating
> > > a
> > > > bad version of some of the core driver model concepts.
> > > > 
> > > > I think the ideal option here would be if drm_aperture could unload
> > > > (unbind really) the platform driver for us, through the driver
> > > > model.
> Then
> > > > there's only one place that keeps track whether the driver is
> > > > unbound
> or
> > > > not. I'm not sure whether this can be done fully generic on a struct
> > > > device, or whether we need special code for each type. Since atm we only
> > > > have simpledrm we can just specialize on platform_device and it's good
> > > > enough.
> > > 
> > > I meanwhile found that calling platform_device_unregister() is the right
> > > thing to do. It is like a hot-unplug event. It's simple to implement and
> > > removes the generic device as well. Any memory ranges for the generic device
> > > are gone as well. Only the native driver's native device will remain. That's
> > > better than the existing simplefb driver.
> > 
> > That sounds great.
> > 
> > > Which unregister function to call still driver-specific, so I kept the
> > > callback.
> > 
> > Could we have the callback in core code, and you do something like
> > drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> > whatever, although tbh I'm not sure we ever get anything else than
> > platform). That function can do a runtime check that drm_device->dev is
> > actually a platform dev.
> 
> Somehow I knew you wouldn't like the current abstraction. :)
> 
> > 
> > Another idea: Do the runtime casting in the core without anything? Atm we
> > have platform that needs support, maybe pci device, so we could easily
> > extend this and just let it do the right thing. Then no callback is
> > needed. I.e.
> > 
> > 	if (is_platform_dev(drm_device->dev))
> > 		platform_device_unregister(drm_device->dev);
> > 	else
> > 		WARN(1, "not yet implemented\n");
> > 
> > or something like that.
> 
> I don't like that. I spend time to remove the usb and pci device pointers
> from code and structs. I don't want to introduce a new hard-coded special
> case here.
> 
> > 
> > I just find the callback to essentially unregister a device a bit
> > redundant.
> 
> I'd like to go with your first idea. The callback would be internal and the
> public acquire function is specifically for firmware-based platform devices.
> That covers simple-framebuffer, VESA, EFI, and probably any other generic
> interface that fbdev supported in the last 20+ yrs. I don't think we'll ever
> need anything else.
> 
> Still, I'd like to have some abstraction between the internals of the
> aperture helpers and our actual use case. I'll update the patchset
> accordingly.

Makes sense and I'm happy with that pick of color choice. That keeps the
noise out of drivers, and also keeps the concepts clean internally.
-Daniel


> 
> Best regards
> Thomas
> 
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > > > ->detach implementatation, and ask for his feedback as driver model
> > > > maintainer. Maybe if you could hack together the platform_device unbind
> > > > path as proof of concept would be even better.
> > > > 
> > > > Either way, this is really tricky.
> > > > -Daniel
> > > > 
> > > > > 
> > > > > Best regards
> > > > > Thomas
> > > > > 
> > > > > > 
> > > > > > Or maybe we should tie this more into the struct device mode and force an
> > > > > > unload that way? That way devm cleanup would work as one expects, and
> > > > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > > > 
> > > > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > > > badly.
> > > > > > 
> > > > > > > + *	};
> > > > > > > + *
> > > > > > > + *	static int acquire_framebuffers(struct
> > > > > > > drm_device *dev, struct
> pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		resource_size_t start, len;
> > > > > > > + *		struct drm_aperture *ap;
> > > > > > > + *
> > > > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > > > + *
> > > > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > > > + *		if (IS_ERR(ap))
> > > > > > > + *			return PTR_ERR(ap);
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		struct drm_device *dev;
> > > > > > > + *		int ret;
> > > > > > > + *
> > > > > > > + *		// ... Initialize the device...
> > > > > > > + *		dev = devm_drm_dev_alloc();
> > > > > > > + *		...
> > > > > > > + *
> > > > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > > > + *		if (ret)
> > > > > > > + *			return ret;
> > > > > > > + *
> > > > > > > + *		drm_dev_register();
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > > > + * like an unplug event.
> > > > > > > + *
> > > > > > > + * .. code-block:: c
> > > > > > > + *
> > > > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > > > + *				       resource_size_t base,
> > > > > > > + *				       resource_size_t size)
> > > > > > > + *	{
> > > > > > > + *		// Signal unplug
> > > > > > > + *		drm_dev_unplug(dev);
> > > > > > > + *
> > > > > > > + *		// Maybe do other clean-up operations
> > > > > > > + *		...
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > > > + *		.detach = detach_from_device,
> > > > > > > + *	};
> > > > > > > + */
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > > > + *
> > > > > > > + * This structure has no public fields.
> > > > > > > + */
> > > > > > > +struct drm_aperture {
> > > > > > > +	struct drm_device *dev;
> > > > > > > +	resource_size_t base;
> > > > > > > +	resource_size_t size;
> > > > > > > +
> > > > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > > > +
> > > > > > > +	struct list_head lh;
> > > > > > > +};
> > > > > > > +
> > > > > > > +static LIST_HEAD(drm_apertures);
> > > > > > > +
> > > > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > > > +
> > > > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > > > +{
> > > > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > > > +{
> > > > > > > +	struct drm_aperture *ap = data;
> > > > > > > +	bool detached = !ap->dev;
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > 
> > > > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > > > 
> > > > > > > +		mutex_lock(&drm_apertures_lock);
> > > > > > 
> > > > > > and an
> > > > > > 
> > > > > > 	else
> > > > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > > > 
> > > > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > > > came up with in my head). But needs comments.
> > > > > > 
> > > > > > > +
> > > > > > > +	list_del(&ap->lh);
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * devm_aperture_acquire - Acquires ownership of a
> > > > > > > framebuffer on
> behalf of a DRM driver.
> > > > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > > > + * @size:	the framebuffer size in bytes
> > > > > > > + * @funcs:	callback functions
> > > > > > > + *
> > > > > > > + * Installs the given device as the new owner. The
> > > > > > > function fails
> if the
> > > > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > > > another
> > > driver.
> > > > > > > + * To evict current owners, callers should use
> > > > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > > > + * function. Acquired apertures are released
> > > > > > > automatically if the
> underlying
> > > > > > > + * device goes away.
> > > > > > > + *
> > > > > > > + * Returns:
> > > > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > > > + * errno value otherwise.
> > > > > > > + */
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > > > +{
> > > > > > > +	size_t end = base + size;
> > > > > > > +	struct list_head *pos;
> > > > > > > +	struct drm_aperture *ap;
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			return ERR_PTR(-EBUSY);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > > > +	if (!ap)
> > > > > > > +		return ERR_PTR(-ENOMEM);
> > > > > > > +
> > > > > > > +	ap->dev = dev;
> > > > > > > +	ap->base = base;
> > > > > > > +	ap->size = size;
> > > > > > > +	ap->funcs = funcs;
> > > > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > > > +
> > > > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > > > +	if (ret)
> > > > > > > +		return ERR_PTR(ret);
> > > > > > > +
> > > > > > > +	return ap;
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > > > +
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > > > +{
> > > > > > > +	resource_size_t end = base + size;
> > > > > > > +	struct list_head *pos, *n;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > > > +		struct drm_aperture *ap =
> > > > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > > > +		struct drm_device *dev = ap->dev;
> > > > > > > +
> > > > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			continue;
> > > > > > > +
> > > > > > > +		ap->dev = NULL; /* detach from device */
> > > > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > > > +			continue;
> > > > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > > > 
> > > > > > Is this just exported because of the inline functions in the
> > > > > > headers?
> > > Imo
> > > > > > better to make them proper functions (they're big after your patch&not
> > > > > > perf critical, so not good candidates for inlining anyway).
> > > > > > 
> > > > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > > > index 13766efe9517..696cec75ef78 100644
> > > > > > > --- a/include/drm/drm_aperture.h
> > > > > > > +++ b/include/drm/drm_aperture.h
> > > > > > > @@ -4,8 +4,30 @@
> > > > > > >     #define _DRM_APERTURE_H_
> > > > > > >     #include <linux/fb.h>
> > > > > > > +#include <linux/pci.h>
> > > > > > >     #include <linux/vgaarb.h>
> > > > > > > +struct drm_aperture;
> > > > > > > +struct drm_device;
> > > > > > > +
> > > > > > > +struct drm_aperture_funcs {
> > > > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > > > +};
> > > > > > > +
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > > > +
> > > > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > > > +#else
> > > > > > > +static inline void
> > > > > > > +drm_aperture_detach_drivers(resource_size_t base,
> > > > > > > resource_size_t
> size)
> > > > > > > +{
> > > > > > > +}
> > > > > > > +#endif
> > > > > > > +
> > > > > > >     /**
> > > > > > >      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > > > >      * @a: memory range, users of which are to be removed
> > > > > > > @@ -20,6 +42,11 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > > > >     					      const char *name, bool primary)
> > > > > > >     {
> > > > > > > +	int i;
> > > > > > > +
> > > > > > > +	for (i = 0; i < a->count; ++i)
> > > > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > > > +
> > > > > > >     #if IS_REACHABLE(CONFIG_FB)
> > > > > > >     	return remove_conflicting_framebuffers(a, name, primary);
> > > > > > >     #else
> > > > > > > @@ -43,7 +70,16 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > > > >     						  const char *name)
> > > > > > >     {
> > > > > > > -	int ret = 0;
> > > > > > > +	resource_size_t base, size;
> > > > > > > +	int bar, ret = 0;
> > > > > > > +
> > > > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > > > +			continue;
> > > > > > > +		base = pci_resource_start(pdev, bar);
> > > > > > > +		size = pci_resource_len(pdev, bar);
> > > > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > > > +	}
> > > > > > >     	/*
> > > > > > >     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > > > -- 
> > > > > > > 2.30.1
> > > > > > > 
> > > > > > 
> > > > > 
> > > > > -- 
> > > > > Thomas Zimmermann
> > > > > Graphics Driver Developer
> > > > > SUSE Software Solutions Germany GmbH
> > > > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > > > (HRB 36809, AG Nürnberg)
> > > > > Geschäftsführer: Felix Imendörffer
> > > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 103+ messages in thread

* Re: [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership
@ 2021-04-16  8:42                 ` Daniel Vetter
  0 siblings, 0 replies; 103+ messages in thread
From: Daniel Vetter @ 2021-04-16  8:42 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: bluescreen_avenger, geert+renesas, corbet, airlied, linux-doc,
	emil.l.velikov, lgirdwood, dri-devel, virtualization, hdegoede,
	broonie, kraxel, sam

On Thu, Apr 15, 2021 at 09:12:14PM +0200, Thomas Zimmermann wrote:
> Hi
> 
> Am 15.04.21 um 14:57 schrieb Daniel Vetter:
> > On Thu, Apr 15, 2021 at 08:56:20AM +0200, Thomas Zimmermann wrote:
> > > Hi
> > > 
> > > Am 09.04.21 um 11:22 schrieb Daniel Vetter:
> > > > > Is it that easy? simepldrm's detach function has code to
> > > > > synchronize
> with
> > > > > concurrent hotplug removals. If we can use drm_dev_unplug() for everything,
> > > > > I'm all for it.
> > > > 
> > > > Uh, I should have looked at the code instead of just asking silly
> > > > questions :-)
> > > > 
> > > > Now I'm even more scared, and also more convinced that we're recreating
> > > a
> > > > bad version of some of the core driver model concepts.
> > > > 
> > > > I think the ideal option here would be if drm_aperture could unload
> > > > (unbind really) the platform driver for us, through the driver
> > > > model.
> Then
> > > > there's only one place that keeps track whether the driver is
> > > > unbound
> or
> > > > not. I'm not sure whether this can be done fully generic on a struct
> > > > device, or whether we need special code for each type. Since atm we only
> > > > have simpledrm we can just specialize on platform_device and it's good
> > > > enough.
> > > 
> > > I meanwhile found that calling platform_device_unregister() is the right
> > > thing to do. It is like a hot-unplug event. It's simple to implement and
> > > removes the generic device as well. Any memory ranges for the generic device
> > > are gone as well. Only the native driver's native device will remain. That's
> > > better than the existing simplefb driver.
> > 
> > That sounds great.
> > 
> > > Which unregister function to call still driver-specific, so I kept the
> > > callback.
> > 
> > Could we have the callback in core code, and you do something like
> > drm_aperture_acquire_platform (and later on drm_aperture_acquire_pci or
> > whatever, although tbh I'm not sure we ever get anything else than
> > platform). That function can do a runtime check that drm_device->dev is
> > actually a platform dev.
> 
> Somehow I knew you wouldn't like the current abstraction. :)
> 
> > 
> > Another idea: Do the runtime casting in the core without anything? Atm we
> > have platform that needs support, maybe pci device, so we could easily
> > extend this and just let it do the right thing. Then no callback is
> > needed. I.e.
> > 
> > 	if (is_platform_dev(drm_device->dev))
> > 		platform_device_unregister(drm_device->dev);
> > 	else
> > 		WARN(1, "not yet implemented\n");
> > 
> > or something like that.
> 
> I don't like that. I spend time to remove the usb and pci device pointers
> from code and structs. I don't want to introduce a new hard-coded special
> case here.
> 
> > 
> > I just find the callback to essentially unregister a device a bit
> > redundant.
> 
> I'd like to go with your first idea. The callback would be internal and the
> public acquire function is specifically for firmware-based platform devices.
> That covers simple-framebuffer, VESA, EFI, and probably any other generic
> interface that fbdev supported in the last 20+ yrs. I don't think we'll ever
> need anything else.
> 
> Still, I'd like to have some abstraction between the internals of the
> aperture helpers and our actual use case. I'll update the patchset
> accordingly.

Makes sense and I'm happy with that pick of color choice. That keeps the
noise out of drivers, and also keeps the concepts clean internally.
-Daniel


> 
> Best regards
> Thomas
> 
> > -Daniel
> > 
> > > 
> > > Best regards
> > > Thomas
> > > 
> > > > 
> > > > I think best here would be to Cc: gregkh on this patch and the simpledrm
> > > > ->detach implementatation, and ask for his feedback as driver model
> > > > maintainer. Maybe if you could hack together the platform_device unbind
> > > > path as proof of concept would be even better.
> > > > 
> > > > Either way, this is really tricky.
> > > > -Daniel
> > > > 
> > > > > 
> > > > > Best regards
> > > > > Thomas
> > > > > 
> > > > > > 
> > > > > > Or maybe we should tie this more into the struct device mode and force an
> > > > > > unload that way? That way devm cleanup would work as one expects, and
> > > > > > avoid the need for anything specific (hopefully) in this detach callback.
> > > > > > 
> > > > > > Just feels a bit like we're reinventing half of the driver model here,
> > > > > > badly.
> > > > > > 
> > > > > > > + *	};
> > > > > > > + *
> > > > > > > + *	static int acquire_framebuffers(struct
> > > > > > > drm_device *dev, struct
> pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		resource_size_t start, len;
> > > > > > > + *		struct drm_aperture *ap;
> > > > > > > + *
> > > > > > > + *		base = pci_resource_start(pdev, 0);
> > > > > > > + *		size = pci_resource_len(pdev, 0);
> > > > > > > + *
> > > > > > > + *		ap = devm_acquire_aperture(dev, base, size, &ap_funcs);
> > > > > > > + *		if (IS_ERR(ap))
> > > > > > > + *			return PTR_ERR(ap);
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static int probe(struct pci_dev *pdev)
> > > > > > > + *	{
> > > > > > > + *		struct drm_device *dev;
> > > > > > > + *		int ret;
> > > > > > > + *
> > > > > > > + *		// ... Initialize the device...
> > > > > > > + *		dev = devm_drm_dev_alloc();
> > > > > > > + *		...
> > > > > > > + *
> > > > > > > + *		// ... and acquire ownership of the framebuffer.
> > > > > > > + *		ret = acquire_framebuffers(dev, pdev);
> > > > > > > + *		if (ret)
> > > > > > > + *			return ret;
> > > > > > > + *
> > > > > > > + *		drm_dev_register();
> > > > > > > + *
> > > > > > > + *		return 0;
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + * The generic driver is now subject to forced removal by other drivers. This
> > > > > > > + * is when the detach function in struct &drm_aperture_funcs comes into play.
> > > > > > > + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al
> > > > > > > + * for the registered framebuffer range, the DRM core calls struct
> > > > > > > + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It
> > > > > > > + * may not access the device's registers, framebuffer memory, ROM, etc after
> > > > > > > + * detach returned. If the driver supports hotplugging, detach can be treated
> > > > > > > + * like an unplug event.
> > > > > > > + *
> > > > > > > + * .. code-block:: c
> > > > > > > + *
> > > > > > > + *	static void detach_from_device(struct drm_device *dev,
> > > > > > > + *				       resource_size_t base,
> > > > > > > + *				       resource_size_t size)
> > > > > > > + *	{
> > > > > > > + *		// Signal unplug
> > > > > > > + *		drm_dev_unplug(dev);
> > > > > > > + *
> > > > > > > + *		// Maybe do other clean-up operations
> > > > > > > + *		...
> > > > > > > + *	}
> > > > > > > + *
> > > > > > > + *	static struct drm_aperture_funcs ap_funcs = {
> > > > > > > + *		.detach = detach_from_device,
> > > > > > > + *	};
> > > > > > > + */
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * struct drm_aperture - Represents a DRM framebuffer aperture
> > > > > > > + *
> > > > > > > + * This structure has no public fields.
> > > > > > > + */
> > > > > > > +struct drm_aperture {
> > > > > > > +	struct drm_device *dev;
> > > > > > > +	resource_size_t base;
> > > > > > > +	resource_size_t size;
> > > > > > > +
> > > > > > > +	const struct drm_aperture_funcs *funcs;
> > > > > > > +
> > > > > > > +	struct list_head lh;
> > > > > > > +};
> > > > > > > +
> > > > > > > +static LIST_HEAD(drm_apertures);
> > > > > > > +
> > > > > > > +static DEFINE_MUTEX(drm_apertures_lock);
> > > > > > > +
> > > > > > > +static bool overlap(resource_size_t base1, resource_size_t end1,
> > > > > > > +		    resource_size_t base2, resource_size_t end2)
> > > > > > > +{
> > > > > > > +	return (base1 < end2) && (end1 > base2);
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void devm_aperture_acquire_release(void *data)
> > > > > > > +{
> > > > > > > +	struct drm_aperture *ap = data;
> > > > > > > +	bool detached = !ap->dev;
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > 
> > > > > > Uh this needs a comment that if ap->dev is NULL then we're called from
> > > > > > drm_aperture_detach_drivers() and hence the lock is already held.
> > > > > > 
> > > > > > > +		mutex_lock(&drm_apertures_lock);
> > > > > > 
> > > > > > and an
> > > > > > 
> > > > > > 	else
> > > > > > 		locdep_assert_held(&drm_apertures_lock);
> > > > > > 
> > > > > > here to check that. I was scratching my head first quite a bit how you'd
> > > > > > solve the deadlock, this is a neat solution (much simpler than anything I
> > > > > > came up with in my head). But needs comments.
> > > > > > 
> > > > > > > +
> > > > > > > +	list_del(&ap->lh);
> > > > > > > +
> > > > > > > +	if (!detached)
> > > > > > > +		mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * devm_aperture_acquire - Acquires ownership of a
> > > > > > > framebuffer on
> behalf of a DRM driver.
> > > > > > > + * @dev:	the DRM device to own the framebuffer memory
> > > > > > > + * @base:	the framebuffer's byte offset in physical memory
> > > > > > > + * @size:	the framebuffer size in bytes
> > > > > > > + * @funcs:	callback functions
> > > > > > > + *
> > > > > > > + * Installs the given device as the new owner. The
> > > > > > > function fails
> if the
> > > > > > > + * framebuffer range, or parts of it, is currently owned by
> > > > > > > another
> > > driver.
> > > > > > > + * To evict current owners, callers should use
> > > > > > > + * drm_fb_helper_remove_conflicting_framebuffers() et al. before calling this
> > > > > > > + * function. Acquired apertures are released
> > > > > > > automatically if the
> underlying
> > > > > > > + * device goes away.
> > > > > > > + *
> > > > > > > + * Returns:
> > > > > > > + * An instance of struct &drm_aperture on success, or a pointer-encoded
> > > > > > > + * errno value otherwise.
> > > > > > > + */
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs)
> > > > > > > +{
> > > > > > > +	size_t end = base + size;
> > > > > > > +	struct list_head *pos;
> > > > > > > +	struct drm_aperture *ap;
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each(pos, &drm_apertures) {
> > > > > > > +		ap = container_of(pos, struct drm_aperture, lh);
> > > > > > > +		if (overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			return ERR_PTR(-EBUSY);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL);
> > > > > > > +	if (!ap)
> > > > > > > +		return ERR_PTR(-ENOMEM);
> > > > > > > +
> > > > > > > +	ap->dev = dev;
> > > > > > > +	ap->base = base;
> > > > > > > +	ap->size = size;
> > > > > > > +	ap->funcs = funcs;
> > > > > > > +	INIT_LIST_HEAD(&ap->lh);
> > > > > > > +
> > > > > > > +	list_add(&ap->lh, &drm_apertures);
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	ret = devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap);
> > > > > > > +	if (ret)
> > > > > > > +		return ERR_PTR(ret);
> > > > > > > +
> > > > > > > +	return ap;
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(devm_aperture_acquire);
> > > > > > > +
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size)
> > > > > > > +{
> > > > > > > +	resource_size_t end = base + size;
> > > > > > > +	struct list_head *pos, *n;
> > > > > > > +
> > > > > > > +	mutex_lock(&drm_apertures_lock);
> > > > > > > +
> > > > > > > +	list_for_each_safe(pos, n, &drm_apertures) {
> > > > > > > +		struct drm_aperture *ap =
> > > > > > > +			container_of(pos, struct drm_aperture, lh);
> > > > > > > +		struct drm_device *dev = ap->dev;
> > > > > > > +
> > > > > > > +		if (!overlap(base, end, ap->base, ap->base + ap->size))
> > > > > > > +			continue;
> > > > > > > +
> > > > > > > +		ap->dev = NULL; /* detach from device */
> > > > > > > +		if (drm_WARN_ON(dev, !ap->funcs->detach))
> > > > > > > +			continue;
> > > > > > > +		ap->funcs->detach(dev, ap->base, ap->size);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	mutex_unlock(&drm_apertures_lock);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL(drm_aperture_detach_drivers);
> > > > > > 
> > > > > > Is this just exported because of the inline functions in the
> > > > > > headers?
> > > Imo
> > > > > > better to make them proper functions (they're big after your patch&not
> > > > > > perf critical, so not good candidates for inlining anyway).
> > > > > > 
> > > > > > > diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h
> > > > > > > index 13766efe9517..696cec75ef78 100644
> > > > > > > --- a/include/drm/drm_aperture.h
> > > > > > > +++ b/include/drm/drm_aperture.h
> > > > > > > @@ -4,8 +4,30 @@
> > > > > > >     #define _DRM_APERTURE_H_
> > > > > > >     #include <linux/fb.h>
> > > > > > > +#include <linux/pci.h>
> > > > > > >     #include <linux/vgaarb.h>
> > > > > > > +struct drm_aperture;
> > > > > > > +struct drm_device;
> > > > > > > +
> > > > > > > +struct drm_aperture_funcs {
> > > > > > > +	void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size);
> > > > > > > +};
> > > > > > > +
> > > > > > > +struct drm_aperture *
> > > > > > > +devm_aperture_acquire(struct drm_device *dev,
> > > > > > > +		      resource_size_t base, resource_size_t size,
> > > > > > > +		      const struct drm_aperture_funcs *funcs);
> > > > > > > +
> > > > > > > +#if defined(CONFIG_DRM_APERTURE)
> > > > > > > +void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size);
> > > > > > > +#else
> > > > > > > +static inline void
> > > > > > > +drm_aperture_detach_drivers(resource_size_t base,
> > > > > > > resource_size_t
> size)
> > > > > > > +{
> > > > > > > +}
> > > > > > > +#endif
> > > > > > > +
> > > > > > >     /**
> > > > > > >      * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
> > > > > > >      * @a: memory range, users of which are to be removed
> > > > > > > @@ -20,6 +42,11 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
> > > > > > >     					      const char *name, bool primary)
> > > > > > >     {
> > > > > > > +	int i;
> > > > > > > +
> > > > > > > +	for (i = 0; i < a->count; ++i)
> > > > > > > +		drm_aperture_detach_drivers(a->ranges[i].base, a->ranges[i].size);
> > > > > > > +
> > > > > > >     #if IS_REACHABLE(CONFIG_FB)
> > > > > > >     	return remove_conflicting_framebuffers(a, name, primary);
> > > > > > >     #else
> > > > > > > @@ -43,7 +70,16 @@ static inline int
> > > > > > >     drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
> > > > > > >     						  const char *name)
> > > > > > >     {
> > > > > > > -	int ret = 0;
> > > > > > > +	resource_size_t base, size;
> > > > > > > +	int bar, ret = 0;
> > > > > > > +
> > > > > > > +	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > > > > > +		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
> > > > > > > +			continue;
> > > > > > > +		base = pci_resource_start(pdev, bar);
> > > > > > > +		size = pci_resource_len(pdev, bar);
> > > > > > > +		drm_aperture_detach_drivers(base, size);
> > > > > > > +	}
> > > > > > >     	/*
> > > > > > >     	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
> > > > > > > -- 
> > > > > > > 2.30.1
> > > > > > > 
> > > > > > 
> > > > > 
> > > > > -- 
> > > > > Thomas Zimmermann
> > > > > Graphics Driver Developer
> > > > > SUSE Software Solutions Germany GmbH
> > > > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > > > (HRB 36809, AG Nürnberg)
> > > > > Geschäftsführer: Felix Imendörffer
> > > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > 
> > > -- 
> > > Thomas Zimmermann
> > > Graphics Driver Developer
> > > SUSE Software Solutions Germany GmbH
> > > Maxfeldstr. 5, 90409 Nürnberg, Germany
> > > (HRB 36809, AG Nürnberg)
> > > Geschäftsführer: Felix Imendörffer
> > > 
> > 
> > 
> > 
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
> 




-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 103+ messages in thread

end of thread, other threads:[~2021-04-16  8:42 UTC | newest]

Thread overview: 103+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-18 10:29 [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs Thomas Zimmermann
2021-03-18 10:29 ` Thomas Zimmermann
2021-03-18 10:29 ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 01/10] drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip() Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 02/10] drm/format-helper: Add blitter functions Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 03/10] drm/aperture: Move fbdev conflict helpers into drm_aperture.h Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-04-08  9:50   ` Daniel Vetter
2021-04-08  9:50     ` Daniel Vetter
2021-04-08  9:50     ` Daniel Vetter
2021-04-09  7:09     ` Thomas Zimmermann
2021-04-09  7:09       ` Thomas Zimmermann
2021-04-09  7:09       ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 04/10] drm/aperture: Add infrastructure for aperture ownership Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-04-08  9:48   ` Daniel Vetter
2021-04-08  9:48     ` Daniel Vetter
2021-04-08  9:48     ` Daniel Vetter
2021-04-09  7:06     ` Thomas Zimmermann
2021-04-09  7:06       ` Thomas Zimmermann
2021-04-09  7:06       ` Thomas Zimmermann
2021-04-09  9:22       ` Daniel Vetter
2021-04-09  9:22         ` Daniel Vetter
2021-04-09  9:22         ` Daniel Vetter
2021-04-15  6:56         ` Thomas Zimmermann
2021-04-15  6:56           ` Thomas Zimmermann
2021-04-15  6:56           ` Thomas Zimmermann
2021-04-15 12:57           ` Daniel Vetter
2021-04-15 12:57             ` Daniel Vetter
2021-04-15 12:57             ` Daniel Vetter
2021-04-15 19:12             ` Thomas Zimmermann
2021-04-15 19:12               ` Thomas Zimmermann
2021-04-15 19:12               ` Thomas Zimmermann
2021-04-16  8:42               ` Daniel Vetter
2021-04-16  8:42                 ` Daniel Vetter
2021-04-16  8:42                 ` Daniel Vetter
2021-04-09  7:54     ` Thomas Zimmermann
2021-04-09  7:54       ` Thomas Zimmermann
2021-04-09  7:54       ` Thomas Zimmermann
2021-04-09  9:29       ` Daniel Vetter
2021-04-09  9:29         ` Daniel Vetter
2021-04-09  9:29         ` Daniel Vetter
2021-03-18 10:29 ` [PATCH v2 05/10] drm: Add simpledrm driver Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 06/10] drm/simpledrm: Add fbdev emulation Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 07/10] drm/simpledrm: Initialize framebuffer data from device-tree node Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 08/10] drm/simpledrm: Acquire clocks from DT device node Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:39   ` Geert Uytterhoeven
2021-03-18 10:39     ` Geert Uytterhoeven
2021-03-18 10:39     ` Geert Uytterhoeven
2021-03-18 11:00     ` Thomas Zimmermann
2021-03-18 11:00       ` Thomas Zimmermann
2021-03-18 11:00       ` Thomas Zimmermann
2021-04-08  8:13   ` Maxime Ripard
2021-04-08  8:13     ` Maxime Ripard
2021-04-15  7:31     ` Thomas Zimmermann
2021-04-15  7:31       ` Thomas Zimmermann
2021-04-15  7:31       ` Thomas Zimmermann
2021-04-15  9:21       ` Maxime Ripard
2021-04-15  9:21         ` Maxime Ripard
2021-04-15 11:02         ` Thomas Zimmermann
2021-04-15 11:02           ` Thomas Zimmermann
2021-04-15 11:02           ` Thomas Zimmermann
2021-04-15 12:11           ` maxime
2021-04-15 12:11             ` maxime
2021-03-18 10:29 ` [PATCH v2 09/10] drm/simpledrm: Acquire regulators " Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29 ` [PATCH v2 10/10] drm/simpledrm: Acquire memory aperture for framebuffer Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-18 10:29   ` Thomas Zimmermann
2021-03-25 11:29 ` [PATCH v2 00/10] drm: Support simple-framebuffer devices and firmware fbs Hans de Goede
2021-03-25 11:29   ` Hans de Goede
2021-03-25 11:29   ` Hans de Goede
2021-03-29 12:31   ` Thomas Zimmermann
2021-03-29 12:31     ` Thomas Zimmermann
2021-03-29 12:31     ` Thomas Zimmermann
2021-03-29 14:50     ` Hans de Goede
2021-03-29 14:50       ` Hans de Goede
2021-03-29 14:50       ` Hans de Goede
2021-03-30  7:09       ` Thomas Zimmermann
2021-03-30  7:09         ` Thomas Zimmermann
2021-03-30  7:09         ` Thomas Zimmermann
2021-03-30  8:34         ` Hans de Goede
2021-03-30  8:34           ` Hans de Goede
2021-03-30  8:34           ` Hans de Goede
2021-04-08 10:14           ` Daniel Vetter
2021-04-08 10:14             ` Daniel Vetter
2021-04-08 10:14             ` Daniel Vetter
2021-03-26  2:31 ` nerdopolis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.