Re: Batched ww-mutexes, wound-wait vs wait-die etc.

2018-04-14 Thread Daniel Vetter
Hi Thomas,

On Fri, Apr 13, 2018 at 10:23 PM, Thomas Hellstrom
 wrote:
> On 04/13/2018 07:13 PM, Daniel Vetter wrote:
>> On Wed, Apr 11, 2018 at 10:27:06AM +0200, Thomas Hellstrom wrote:
>>> 2) Should we add a *real* wound-wait choice to our wound-wait mutexes.
>>> Otherwise perhaps rename them or document that they're actually doing
>>> wait-die.
>>
>> I think a doc patch would be good at least. Including all the data you
>> assembled here.
>
>
> Actually, a further investigation appears to indicate that manipulating the
> lock state under a local spinlock is about fast as using atomic operations
> even for the completely uncontended cases.
>
> This means that we could have a solution where you decide on a per-mutex or
> per-reservation object basis whether you want to manipulate lock-state under
> a "batch group" spinlock, meaning certain performance characteristics or
> traditional local locking, meaning other performance characteristics.
>
> Like, vmwgfx could choose batching locks, radeon traditional locks, but the
> same API would work for both and locks could be shared between drivers..

Don't we need to make this decision at least on a per-class level? Or
how will the spinlock/batch-lock approach interact with the normal
ww_mutex_lock path (which does require the atomics/ordered stores
we're trying to avoid)?

If we can't mix them I'm kinda leaning towards a
ww_batch_mutex/ww_batch_acquire_ctx, but exactly matching api
otherwise. We probably do need the new batch_start/end api, since
ww_acquire_done isn't quite the right place ...

> I'll see if I get time to put together an RFC.

Yeah I think there's definitely some use for batched ww locks, where
parallelism is generally low, or at least the ratio between "time
spent acquiring locks" and "time spent doing stuff while holding
locks" small enough to not make the reduced parallelism while
acquiring an issue.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[DPU PATCH v2 1/2] drm/panel: Add Truly NT35597 panel

2018-04-14 Thread Abhinav Kumar
From: Archit Taneja 

Add support for Truly NT35597 panel used
in MSM reference platforms.

Changes in v2:
- Renamed panel to truly,nt35597
- Added SPDX license
- Used endpoints instead of custom node
- Renamed and cleaned up power supplies

Signed-off-by: Archit Taneja 
Signed-off-by: Abhinav Kumar 
---
 .../devicetree/bindings/display/truly,nt35597.txt  |  47 ++
 drivers/gpu/drm/panel/Kconfig  |   7 +
 drivers/gpu/drm/panel/Makefile |   1 +
 drivers/gpu/drm/panel/panel-truly-nt35597.c| 597 +
 4 files changed, 652 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/truly,nt35597.txt
 create mode 100644 drivers/gpu/drm/panel/panel-truly-nt35597.c

diff --git a/Documentation/devicetree/bindings/display/truly,nt35597.txt 
b/Documentation/devicetree/bindings/display/truly,nt35597.txt
new file mode 100644
index 000..22b6f19
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/truly,nt35597.txt
@@ -0,0 +1,47 @@
+Truly model NT35597 1440x2560 DSI Panel
+
+Required properties:
+- compatible: should be "truly,nt35597"
+- vdda-supply: phandle of the regulator that provides the supply voltage
+  Power IC supply
+- vdispp-supply: phandle of the regulator that provides the supply voltage
+  for positive LCD bias
+- vdispn-supply: phandle of the regulator that provides the supply voltage
+  for negative LCD bias
+- reset-gpios: phandle of gpio for reset line
+  This should be 8mA, gpio can be configured using mux, pinctrl, pinctrl-names
+- mode-gpios: phandle of the gpio for choosing the mode of the display
+  for single DSI or Dual DSI
+  This should be low for dual DSI and high for single DSI mode
+- display-timings: Node for the Panel timings
+
+Example:
+
+   dsi@ae94000 {
+   panel@0 {
+   compatible = "truly,nt35597";
+   reg = <0>;
+   vdda-supply = <_l14>;
+   vdispp-supply = <_regulator>;
+   vdispn-supply = <_regulator>;
+   pinctrl-names = "default", "suspend";
+   pinctrl-0 = <_dsi_active>;
+   pinctrl-1 = <_dsi_suspend>;
+
+   reset-gpios = < 6 0>;
+   mode-gpios = < 52 0>;
+   display-timings {
+   timing0: timing-0 {
+   clock-frequency = <268316138>;
+   hactive = <1440>;
+   vactive = <2560>;
+   hfront-porch = <200>;
+   hback-porch = <64>;
+   hsync-len = <32>;
+   vfront-porch = <8>;
+   vback-porch = <7>;
+   vsync-len = <1>;
+   };
+   };
+   };
+   };
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 988048e..9f0c490 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -168,4 +168,11 @@ config DRM_PANEL_SITRONIX_ST7789V
  Say Y here if you want to enable support for the Sitronix
  ST7789V controller for 240x320 LCD panels
 
+config DRM_PANEL_TRULY_NT35597_WQXGA
+   tristate "Truly WQXGA"
+   depends on OF
+   depends on DRM_MIPI_DSI
+   help
+ Say Y here if you want to enable support for Truly NT35597 WQXGA Dual 
DSI
+ Video Mode panel
 endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 3d2a88d..b5b4b60 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
+obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c 
b/drivers/gpu/drm/panel/panel-truly-nt35597.c
new file mode 100644
index 000..5bd5fdc
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or 

[DPU PATCH v2 2/2] drm/panel: add backlight control support for truly panel

2018-04-14 Thread Abhinav Kumar
Register truly panel as a backlight led device and
provide methods to control its backlight operation.

Changes in v2:
- Removed redundant NULL checks
- Arranged headers alphabetically
- Formatting fixes

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/panel/panel-truly-nt35597.c | 91 +
 1 file changed, 91 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c 
b/drivers/gpu/drm/panel/panel-truly-nt35597.c
index 5bd5fdc..ec9f973 100644
--- a/drivers/gpu/drm/panel/panel-truly-nt35597.c
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -13,6 +13,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -25,6 +26,9 @@
 #include 
 #include 
 
+#define BL_NODE_NAME_SIZE 32
+#define PRIM_DISPLAY_NODE 0
+
 static const char * const regulator_names[] = {
"vdda",
"vdispp",
@@ -51,6 +55,8 @@ struct truly_wqxga {
struct gpio_desc *mode_gpio;
 
struct backlight_device *backlight;
+   /* WLED params */
+   struct led_trigger *wled;
struct videomode vm;
 
struct mipi_dsi_device *dsi[2];
@@ -454,6 +460,82 @@ static void truly_wqxga_panel_del(struct truly_wqxga *ctx)
drm_panel_remove(>panel);
 }
 
+static void truly_wqxga_bkl_unregister(struct truly_wqxga *ctx)
+{
+   if (ctx->backlight)
+   put_device(>backlight->dev);
+}
+
+static int truly_backlight_device_update_status(struct backlight_device *bd)
+{
+   int brightness;
+   int max_brightness;
+   int rc = 0;
+   struct truly_wqxga *ctx = dev_get_drvdata(>dev);
+
+   brightness = bd->props.brightness;
+   max_brightness = bd->props.max_brightness;
+
+   if ((bd->props.power != FB_BLANK_UNBLANK) ||
+   (bd->props.state & BL_CORE_FBBLANK) ||
+ (bd->props.state & BL_CORE_SUSPENDED))
+   brightness = 0;
+
+   if (brightness > max_brightness)
+   brightness = max_brightness;
+
+   if (ctx->wled)
+   led_trigger_event(ctx->wled, brightness);
+
+   return rc;
+}
+
+static int truly_backlight_device_get_brightness(struct backlight_device *bd)
+{
+   return bd->props.brightness;
+}
+
+static const struct backlight_ops truly_backlight_device_ops = {
+   .update_status = truly_backlight_device_update_status,
+   .get_brightness = truly_backlight_device_get_brightness,
+};
+
+static int truly_backlight_setup(struct truly_wqxga *ctx)
+{
+   struct backlight_properties props;
+   char bl_node_name[BL_NODE_NAME_SIZE];
+
+   if (!ctx->backlight) {
+   memset(, 0, sizeof(props));
+   props.type = BACKLIGHT_RAW;
+   props.power = FB_BLANK_UNBLANK;
+   props.max_brightness = 4096;
+
+   snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
+PRIM_DISPLAY_NODE);
+
+   ctx->backlight =  backlight_device_register(bl_node_name,
+   ctx->dev, ctx,
+   _backlight_device_ops, );
+
+   if (IS_ERR_OR_NULL(ctx->backlight)) {
+   pr_err("Failed to register backlight\n");
+   ctx->backlight = NULL;
+   return -ENODEV;
+   }
+
+   /* Register with the LED driver interface */
+   led_trigger_register_simple("bkl-trigger", >wled);
+
+   if (!ctx->wled) {
+   pr_err("backlight led registration failed\n");
+   return -ENODEV;
+   }
+   }
+
+   return 0;
+}
+
 static int truly_wqxga_probe(struct mipi_dsi_device *dsi)
 {
struct device *dev = >dev;
@@ -530,6 +612,12 @@ static int truly_wqxga_probe(struct mipi_dsi_device *dsi)
goto err_panel_add;
}
 
+   ret = truly_backlight_setup(ctx);
+   if (ret) {
+   dev_err(dev, "backlight setup failed\n");
+   goto err_backlight;
+   }
+
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "master dsi attach failed\n");
@@ -549,6 +637,8 @@ static int truly_wqxga_probe(struct mipi_dsi_device *dsi)
 err_dsi_attach_sec:
mipi_dsi_detach(ctx->dsi[0]);
 err_dsi_attach:
+   truly_wqxga_bkl_unregister(ctx);
+err_backlight:
truly_wqxga_panel_del(ctx);
 err_panel_add:
mipi_dsi_device_unregister(secondary);
@@ -570,6 +660,7 @@ static int truly_wqxga_remove(struct mipi_dsi_device *dsi)
mipi_dsi_detach(ctx->dsi[1]);
mipi_dsi_device_unregister(ctx->dsi[1]);
}
+   truly_wqxga_bkl_unregister(ctx);
truly_wqxga_panel_del(ctx);
kfree(ctx);
}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


[Bug 105145] vaExportSurfaceHandle interaction with surface interlaced flag prevents switching on vaapi deinterlacing dynamically

2018-04-14 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=105145

--- Comment #10 from tempel.jul...@gmail.com ---
The PR got merged.

-- 
You are receiving this mail because:
You are the assignee for the bug.___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC v4 08/25] drm/fb-helper: Use struct drm_client_display

2018-04-14 Thread Noralf Trønnes
Prepare to move the modeset committing code to drm_client.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 161 
 include/drm/drm_fb_helper.h |   8 ++
 2 files changed, 89 insertions(+), 80 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2eef24db21f8..bdb4b57d2c12 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -321,13 +322,14 @@ static bool drm_fb_helper_panel_rotation(struct 
drm_connector *connector,
return true;
 }
 
-static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool 
active)
+static int drm_client_display_restore_atomic(struct drm_client_display 
*display, bool active)
 {
-   struct drm_device *dev = fb_helper->dev;
+   struct drm_device *dev = display->dev;
struct drm_plane_state *plane_state;
+   struct drm_mode_set *mode_set;
struct drm_plane *plane;
struct drm_atomic_state *state;
-   int i, ret;
+   int ret;
unsigned int plane_mask;
struct drm_modeset_acquire_ctx ctx;
 
@@ -363,8 +365,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper 
*fb_helper, bool activ
goto out_state;
}
 
-   for (i = 0; i < fb_helper->crtc_count; i++) {
-   struct drm_mode_set *mode_set = 
_helper->crtc_info[i].mode_set;
+   drm_client_display_for_each_modeset(mode_set, display) {
struct drm_plane *primary = mode_set->crtc->primary;
unsigned int rotation;
 
@@ -412,13 +413,14 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper 
*fb_helper, bool activ
goto retry;
 }
 
-static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
+static int drm_client_display_restore_legacy(struct drm_client_display 
*display)
 {
-   struct drm_device *dev = fb_helper->dev;
+   struct drm_device *dev = display->dev;
+   struct drm_mode_set *mode_set;
struct drm_plane *plane;
-   int i, ret = 0;
+   int ret = 0;
 
-   drm_modeset_lock_all(fb_helper->dev);
+   drm_modeset_lock_all(dev);
drm_for_each_plane(plane, dev) {
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
drm_plane_force_disable(plane);
@@ -429,8 +431,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper 
*fb_helper)
DRM_MODE_ROTATE_0);
}
 
-   for (i = 0; i < fb_helper->crtc_count; i++) {
-   struct drm_mode_set *mode_set = 
_helper->crtc_info[i].mode_set;
+   drm_client_display_for_each_modeset(mode_set, display) {
struct drm_crtc *crtc = mode_set->crtc;
 
if (crtc->funcs->cursor_set2) {
@@ -448,19 +449,17 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper 
*fb_helper)
goto out;
}
 out:
-   drm_modeset_unlock_all(fb_helper->dev);
+   drm_modeset_unlock_all(dev);
 
return ret;
 }
 
-static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+static int drm_client_display_restore(struct drm_client_display *display)
 {
-   struct drm_device *dev = fb_helper->dev;
-
-   if (drm_drv_uses_atomic_modeset(dev))
-   return restore_fbdev_mode_atomic(fb_helper, true);
+   if (drm_drv_uses_atomic_modeset(display->dev))
+   return drm_client_display_restore_atomic(display, true);
else
-   return restore_fbdev_mode_legacy(fb_helper);
+   return drm_client_display_restore_legacy(display);
 }
 
 /**
@@ -486,7 +485,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct 
drm_fb_helper *fb_helper)
return 0;
 
mutex_lock(_helper->lock);
-   ret = restore_fbdev_mode(fb_helper);
+   ret = drm_client_display_restore(fb_helper->display);
 
do_delayed = fb_helper->delayed_hotplug;
if (do_delayed)
@@ -548,7 +547,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
continue;
 
mutex_lock(>lock);
-   ret = restore_fbdev_mode(helper);
+   ret = drm_client_display_restore(helper->display);
if (ret)
error = true;
mutex_unlock(>lock);
@@ -580,22 +579,20 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op 
= {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
+static void drm_client_display_dpms_legacy(struct drm_client_display *display, 
int dpms_mode)
 {
-   struct drm_device *dev = fb_helper->dev;
+   struct drm_device *dev = display->dev;
struct drm_connector *connector;
struct drm_mode_set *modeset;
-   

[RFC v4 04/25] drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()

2018-04-14 Thread Noralf Trønnes
Atomic drivers can't use them so finish what was started in
commit 9c79e0b1d096 ("drm/fb-helper: Give up on kgdb for atomic drivers").

This prepares the ground for creating modesets on demand.

TODO:
- Actually remove the functions, not just the contents.
- Nuke drm_crtc_helper_funcs->mode_set_base_atomic
- Documentation/dev-tools/kgdb.rst

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 82 -
 1 file changed, 82 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e48ace2d55f5..06e94de6452a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -267,96 +267,14 @@ int drm_fb_helper_remove_one_connector(struct 
drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
 
-static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
-{
-   uint16_t *r_base, *g_base, *b_base;
-
-   if (crtc->funcs->gamma_set == NULL)
-   return;
-
-   r_base = crtc->gamma_store;
-   g_base = r_base + crtc->gamma_size;
-   b_base = g_base + crtc->gamma_size;
-
-   crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
-  crtc->gamma_size, NULL);
-}
-
-/**
- * drm_fb_helper_debug_enter - implementation for _ops.fb_debug_enter
- * @info: fbdev registered by the helper
- */
 int drm_fb_helper_debug_enter(struct fb_info *info)
 {
-   struct drm_fb_helper *helper = info->par;
-   const struct drm_crtc_helper_funcs *funcs;
-   int i;
-
-   list_for_each_entry(helper, _fb_helper_list, kernel_fb_list) {
-   for (i = 0; i < helper->crtc_count; i++) {
-   struct drm_mode_set *mode_set =
-   >crtc_info[i].mode_set;
-
-   if (!mode_set->crtc->enabled)
-   continue;
-
-   funcs = mode_set->crtc->helper_private;
-   if (funcs->mode_set_base_atomic == NULL)
-   continue;
-
-   if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
-   continue;
-
-   funcs->mode_set_base_atomic(mode_set->crtc,
-   mode_set->fb,
-   mode_set->x,
-   mode_set->y,
-   ENTER_ATOMIC_MODE_SET);
-   }
-   }
-
return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
 
-/**
- * drm_fb_helper_debug_leave - implementation for _ops.fb_debug_leave
- * @info: fbdev registered by the helper
- */
 int drm_fb_helper_debug_leave(struct fb_info *info)
 {
-   struct drm_fb_helper *helper = info->par;
-   struct drm_crtc *crtc;
-   const struct drm_crtc_helper_funcs *funcs;
-   struct drm_framebuffer *fb;
-   int i;
-
-   for (i = 0; i < helper->crtc_count; i++) {
-   struct drm_mode_set *mode_set = >crtc_info[i].mode_set;
-
-   crtc = mode_set->crtc;
-   if (drm_drv_uses_atomic_modeset(crtc->dev))
-   continue;
-
-   funcs = crtc->helper_private;
-   fb = crtc->primary->fb;
-
-   if (!crtc->enabled)
-   continue;
-
-   if (!fb) {
-   DRM_ERROR("no fb to restore??\n");
-   continue;
-   }
-
-   if (funcs->mode_set_base_atomic == NULL)
-   continue;
-
-   drm_fb_helper_restore_lut_atomic(mode_set->crtc);
-   funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
-   crtc->y, LEAVE_ATOMIC_MODE_SET);
-   }
-
return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
-- 
2.15.1

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


[RFC v4 01/25] drm: provide management functions for drm_file

2018-04-14 Thread Noralf Trønnes
From: David Herrmann 

Rather than doing drm_file allocation/destruction right in the fops, lets
provide separate helpers. This decouples drm_file management from the
still-mandatory drm-fops. It prepares for use of drm_file without the
fops, both by possible separate fops implementations and APIs (not that I
am aware of any such plans), and more importantly from in-kernel use where
no real file is available.

Signed-off-by: David Herrmann 
Signed-off-by: Noralf Trønnes 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_file.c | 305 +++--
 drivers/gpu/drm/drm_internal.h |   2 +
 2 files changed, 175 insertions(+), 132 deletions(-)

diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index e394799979a6..d4588d33f91c 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -101,6 +101,175 @@ DEFINE_MUTEX(drm_global_mutex);
 
 static int drm_open_helper(struct file *filp, struct drm_minor *minor);
 
+/**
+ * drm_file_alloc - allocate file context
+ * @minor: minor to allocate on
+ *
+ * This allocates a new DRM file context. It is not linked into any context and
+ * can be used by the caller freely. Note that the context keeps a pointer to
+ * @minor, so it must be freed before @minor is.
+ *
+ * RETURNS:
+ * Pointer to newly allocated context, ERR_PTR on failure.
+ */
+struct drm_file *drm_file_alloc(struct drm_minor *minor)
+{
+   struct drm_device *dev = minor->dev;
+   struct drm_file *file;
+   int ret;
+
+   file = kzalloc(sizeof(*file), GFP_KERNEL);
+   if (!file)
+   return ERR_PTR(-ENOMEM);
+
+   file->pid = get_pid(task_pid(current));
+   file->minor = minor;
+
+   /* for compatibility root is always authenticated */
+   file->authenticated = capable(CAP_SYS_ADMIN);
+   file->lock_count = 0;
+
+   INIT_LIST_HEAD(>lhead);
+   INIT_LIST_HEAD(>fbs);
+   mutex_init(>fbs_lock);
+   INIT_LIST_HEAD(>blobs);
+   INIT_LIST_HEAD(>pending_event_list);
+   INIT_LIST_HEAD(>event_list);
+   init_waitqueue_head(>event_wait);
+   file->event_space = 4096; /* set aside 4k for event buffer */
+
+   mutex_init(>event_read_lock);
+
+   if (drm_core_check_feature(dev, DRIVER_GEM))
+   drm_gem_open(dev, file);
+
+   if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+   drm_syncobj_open(file);
+
+   if (drm_core_check_feature(dev, DRIVER_PRIME))
+   drm_prime_init_file_private(>prime);
+
+   if (dev->driver->open) {
+   ret = dev->driver->open(dev, file);
+   if (ret < 0)
+   goto out_prime_destroy;
+   }
+
+   if (drm_is_primary_client(file)) {
+   ret = drm_master_open(file);
+   if (ret)
+   goto out_close;
+   }
+
+   return file;
+
+out_close:
+   if (dev->driver->postclose)
+   dev->driver->postclose(dev, file);
+out_prime_destroy:
+   if (drm_core_check_feature(dev, DRIVER_PRIME))
+   drm_prime_destroy_file_private(>prime);
+   if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+   drm_syncobj_release(file);
+   if (drm_core_check_feature(dev, DRIVER_GEM))
+   drm_gem_release(dev, file);
+   put_pid(file->pid);
+   kfree(file);
+
+   return ERR_PTR(ret);
+}
+
+static void drm_events_release(struct drm_file *file_priv)
+{
+   struct drm_device *dev = file_priv->minor->dev;
+   struct drm_pending_event *e, *et;
+   unsigned long flags;
+
+   spin_lock_irqsave(>event_lock, flags);
+
+   /* Unlink pending events */
+   list_for_each_entry_safe(e, et, _priv->pending_event_list,
+pending_link) {
+   list_del(>pending_link);
+   e->file_priv = NULL;
+   }
+
+   /* Remove unconsumed events */
+   list_for_each_entry_safe(e, et, _priv->event_list, link) {
+   list_del(>link);
+   kfree(e);
+   }
+
+   spin_unlock_irqrestore(>event_lock, flags);
+}
+
+/**
+ * drm_file_free - free file context
+ * @file: context to free, or NULL
+ *
+ * This destroys and deallocates a DRM file context previously allocated via
+ * drm_file_alloc(). The caller must make sure to unlink it from any contexts
+ * before calling this.
+ *
+ * If NULL is passed, this is a no-op.
+ *
+ * RETURNS:
+ * 0 on success, or error code on failure.
+ */
+void drm_file_free(struct drm_file *file)
+{
+   struct drm_device *dev;
+
+   if (!file)
+   return;
+
+   dev = file->minor->dev;
+
+   DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
+ task_pid_nr(current),
+ (long)old_encode_dev(file->minor->kdev->devt),
+ dev->open_count);
+
+   if (drm_core_check_feature(dev, 

[RFC v4 03/25] drm/fb-helper: No need to cache rotation and sw_rotations

2018-04-14 Thread Noralf Trønnes
Getting rotation info is cheap so we can do it on demand.

This is done in preparation for the removal of struct drm_fb_helper_crtc.

Cc: Hans de Goede 
Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 131 
 include/drm/drm_fb_helper.h |   8 ---
 2 files changed, 65 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0646b108030b..e48ace2d55f5 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -361,6 +361,48 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+/* Check if the plane can hw rotate to match panel orientation */
+static bool drm_fb_helper_panel_rotation(struct drm_connector *connector,
+struct drm_plane *plane,
+unsigned int *rotation)
+{
+   uint64_t valid_mask = 0;
+   unsigned int i;
+
+   if (!connector)
+   return false;
+
+   switch (connector->display_info.panel_orientation) {
+   case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+   *rotation = DRM_MODE_ROTATE_180;
+   break;
+   case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+   *rotation = DRM_MODE_ROTATE_90;
+   break;
+   case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+   *rotation = DRM_MODE_ROTATE_270;
+   break;
+   default:
+   *rotation = DRM_MODE_ROTATE_0;
+   }
+
+   /*
+* TODO: support 90 / 270 degree hardware rotation,
+* depending on the hardware this may require the framebuffer
+* to be in a specific tiling format.
+*/
+   if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+   return false;
+
+   for (i = 0; i < plane->rotation_property->num_values; i++)
+   valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+   if (!(*rotation & valid_mask))
+   return false;
+
+   return true;
+}
+
 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool 
active)
 {
struct drm_device *dev = fb_helper->dev;
@@ -406,10 +448,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper 
*fb_helper, bool activ
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = 
_helper->crtc_info[i].mode_set;
struct drm_plane *primary = mode_set->crtc->primary;
+   unsigned int rotation;
 
-   /* Cannot fail as we've already gotten the plane state above */
-   plane_state = drm_atomic_get_new_plane_state(state, primary);
-   plane_state->rotation = fb_helper->crtc_info[i].rotation;
+   if (drm_fb_helper_panel_rotation(mode_set->connectors[0], 
primary, )) {
+   /* Cannot fail as we've already gotten the plane state 
above */
+   plane_state = drm_atomic_get_new_plane_state(state, 
primary);
+   plane_state->rotation = rotation;
+   }
 
ret = __drm_atomic_helper_set_config(mode_set, state);
if (ret != 0)
@@ -841,7 +886,6 @@ int drm_fb_helper_init(struct drm_device *dev,
if (!fb_helper->crtc_info[i].mode_set.connectors)
goto out_free;
fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-   fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
}
 
i = 0;
@@ -2414,62 +2458,6 @@ static int drm_pick_crtcs(struct drm_fb_helper 
*fb_helper,
return best_score;
 }
 
-/*
- * This function checks if rotation is necessary because of panel orientation
- * and if it is, if it is supported.
- * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
- * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
- * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
- * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
- * the unsupported rotation.
- */
-static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
-   struct drm_fb_helper_crtc *fb_crtc,
-   struct drm_connector *connector)
-{
-   struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
-   uint64_t valid_mask = 0;
-   int i, rotation;
-
-   fb_crtc->rotation = DRM_MODE_ROTATE_0;
-
-   switch (connector->display_info.panel_orientation) {
-   case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
-   rotation = DRM_MODE_ROTATE_180;
-   break;
-   case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
-   rotation = DRM_MODE_ROTATE_90;
-   break;
-   case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
-   

[RFC v4 00/25] drm: Add generic fbdev emulation

2018-04-14 Thread Noralf Trønnes
This patchset explores the possibility of having generic fbdev emulation
in DRM for drivers that supports dumb buffers which they can export. An
API is added to support in-kernel clients in general.

In this version I was able to reuse the modesetting code from
drm_fb_helper in the client API. This avoids code duplication, carries
over lessons learned and the modesetting code is bisectable. The
downside is that it takes +10 patches to rip drm_fb_helper in two, so
maybe it's not worth it wrt possible breakage and a challenging review.

Does the Intel CI test the fbdev emulation?

Daniel had this concern with the previous version:

The register/unregister model needs more thought. Allowing both clients
to register whenever they want to, and drm_device instances to come and
go is what fbcon has done, and the resulting locking is a horror show.

I think if we require that all in-kernel drm_clients are registers when
loading drm.ko (and enabled/disabled only per module options and
Kconfig), then we can throw out all the locking. That avoids a lot of
the headaches.

I have solved this by adding a notifier that fires when a new DRM device
is registered (I've removed the new() callback). Currently only
bootsplash uses this. The fbdev client needs to be setup from the driver
since it can't know on device registration if the driver will setup it's
own fbdev emulation later and the vtcon client hooks up to a user
provided device id.

Since fbcon can't handle fb_open failing, the buffer has to be
pre-allocated. Exporting a GEM buffer pins the driver module making it
impossible to unload it.
I have included 2 solutions to the problem:
- sysfs file to remove/close clients: remove_internal_clients
- Change drm_gem_prime_export() so it doesn't pin on client buffers

If a dumb buffer is exported from a kernel thread (worker) context, the
file descriptor isn't closed and I leak a reference so the buffer isn't
freed. Please look at drm_client_buffer_create() in patch
'drm/client: Finish the in-kernel client API'.
This is a blocker that needs a solution.


Noralf.

Changes since version 3:
Client API changes:
- Drop drm_client_register_funcs() which attached clients indirectly.
  Let clients attach directly using drm_client_new{_from_id}(). Clients
  that wants to attach to all devices must be linked into drm.ko and use
  the DRM device notifier. This is done to avoid the lock/race
  register/unregister hell we have with fbcon. (Daniel Vetter)
- drm_client_display_restore() checks if there is a master and if so
  returns -EBUSY. (Daniel Vetter)
- Allocate drm_file up front instead of on-demand. Since fbdev can't do
  on demand buffer allocation because of fbcon, there's no need for this.
- Add sysfs file to remove clients
- Don't pin driver module when exporting gem client buffers
- Dropped page flip support since drm_fb_helper is now used for fbdev
  emulation.

- The bootsplash client now switches over to fbdev on keypress.

Changes since version 2:
- Don't set drm master for in-kernel clients. (Daniel Vetter)
- Add in-kernel client API

Changes since version 1:
- Don't add drm_fb_helper_fb_open() and drm_fb_helper_fb_release() to
  DRM_FB_HELPER_DEFAULT_OPS(). (Fi.CI.STATIC)
  The following uses that macro and sets fb_open/close: udlfb_ops,
  amdgpufb_ops, drm_fb_helper_generic_fbdev_ops, nouveau_fbcon_ops,
  nouveau_fbcon_sw_ops, radeonfb_ops.
  This results in: warning: Initializer entry defined twice
- Support CONFIG_DRM_KMS_HELPER=m (kbuild test robot)
  ERROR:  [drivers/gpu/drm/drm_kms_helper.ko] undefined!
- Drop buggy patch: (Chris Wilson)
  drm/prime: Clear drm_gem_object->dma_buf on release
- Defer buffer creation until fb_open.


David Herrmann (1):
  drm: provide management functions for drm_file

Noralf Trønnes (24):
  drm/file: Don't set master on in-kernel clients
  drm/fb-helper: No need to cache rotation and sw_rotations
  drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()
  drm/fb-helper: dpms_legacy(): Only set on connectors in use
  drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  drm: Begin an API for in-kernel clients
  drm/fb-helper: Use struct drm_client_display
  drm/fb-helper: Move modeset commit code to drm_client
  drm/connector: Add
drm_connector_has_preferred_mode/pick_cmdline_mode()
  drm/connector: Add connector array functions
  drm/i915: Add drm_driver->initial_client_display callback
  drm/fb-helper: Remove struct drm_fb_helper_crtc
  drm/fb-helper: Remove struct drm_fb_helper_connector
  drm/fb-helper: Move modeset config code to drm_client
  drm: Make ioctls available for in-kernel clients
  drm/client: Bail out if there's a DRM master
  drm/client: Make the display modes available to clients
  drm/client: Finish the in-kernel client API
  drm/prime: Don't pin module on export for in-kernel clients
  drm/fb-helper: Add drm_fb_helper_fb_open/release()
  drm/fb-helper: Add generic fbdev emulation
  drm: Add DRM device registered 

[RFC v4 02/25] drm/file: Don't set master on in-kernel clients

2018-04-14 Thread Noralf Trønnes
It only makes sense for userspace clients.

Signed-off-by: Noralf Trønnes 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_file.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index d4588d33f91c..55505378df47 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -155,17 +155,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
goto out_prime_destroy;
}
 
-   if (drm_is_primary_client(file)) {
-   ret = drm_master_open(file);
-   if (ret)
-   goto out_close;
-   }
-
return file;
 
-out_close:
-   if (dev->driver->postclose)
-   dev->driver->postclose(dev, file);
 out_prime_destroy:
if (drm_core_check_feature(dev, DRIVER_PRIME))
drm_prime_destroy_file_private(>prime);
@@ -365,6 +356,7 @@ static int drm_open_helper(struct file *filp, struct 
drm_minor *minor)
 {
struct drm_device *dev = minor->dev;
struct drm_file *priv;
+   int ret;
 
if (filp->f_flags & O_EXCL)
return -EBUSY;  /* No exclusive opens */
@@ -379,6 +371,14 @@ static int drm_open_helper(struct file *filp, struct 
drm_minor *minor)
if (IS_ERR(priv))
return PTR_ERR(priv);
 
+   if (drm_is_primary_client(priv)) {
+   ret = drm_master_open(priv);
+   if (ret) {
+   drm_file_free(priv);
+   return ret;
+   }
+   }
+
filp->private_data = priv;
priv->filp = filp;
 
-- 
2.15.1

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


[RFC v4 09/25] drm/fb-helper: Move modeset commit code to drm_client

2018-04-14 Thread Noralf Trønnes
This moves the committing part of the modesetting code to drm_client.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c| 242 
 drivers/gpu/drm/drm_fb_helper.c | 216 +--
 include/drm/drm_client.h|   8 ++
 3 files changed, 252 insertions(+), 214 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 7c31a6efb2f4..c85c13568cf9 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -10,6 +10,8 @@
 
 #include 
 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -117,3 +119,243 @@ drm_client_display_find_modeset(struct drm_client_display 
*display, struct drm_c
return NULL;
 }
 EXPORT_SYMBOL(drm_client_display_find_modeset);
+
+/**
+ * drm_client_display_panel_rotation() - Check panel orientation
+ * @connector: DRM connector
+ * @plane: DRM plane
+ * @rotation: Returned rotation value
+ *
+ * This function checks if @plane can hw rotate to match the panel orientation
+ * on @connector.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_display_panel_rotation(struct drm_connector *connector,
+  struct drm_plane *plane,
+  unsigned int *rotation)
+{
+   uint64_t valid_mask = 0;
+   unsigned int i;
+
+   if (!connector)
+   return false;
+
+   switch (connector->display_info.panel_orientation) {
+   case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+   *rotation = DRM_MODE_ROTATE_180;
+   break;
+   case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+   *rotation = DRM_MODE_ROTATE_90;
+   break;
+   case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+   *rotation = DRM_MODE_ROTATE_270;
+   break;
+   default:
+   *rotation = DRM_MODE_ROTATE_0;
+   }
+
+   /*
+* TODO: support 90 / 270 degree hardware rotation,
+* depending on the hardware this may require the framebuffer
+* to be in a specific tiling format.
+*/
+   if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+   return false;
+
+   for (i = 0; i < plane->rotation_property->num_values; i++)
+   valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+   if (!(*rotation & valid_mask))
+   return false;
+
+   return true;
+}
+EXPORT_SYMBOL(drm_client_display_panel_rotation);
+
+static int drm_client_display_restore_atomic(struct drm_client_display 
*display, bool active)
+{
+   struct drm_device *dev = display->dev;
+   struct drm_plane_state *plane_state;
+   struct drm_mode_set *mode_set;
+   struct drm_plane *plane;
+   struct drm_atomic_state *state;
+   int ret;
+   unsigned int plane_mask;
+   struct drm_modeset_acquire_ctx ctx;
+
+   drm_modeset_acquire_init(, 0);
+
+   state = drm_atomic_state_alloc(dev);
+   if (!state) {
+   ret = -ENOMEM;
+   goto out_ctx;
+   }
+
+   state->acquire_ctx = 
+retry:
+   plane_mask = 0;
+   drm_for_each_plane(plane, dev) {
+   plane_state = drm_atomic_get_plane_state(state, plane);
+   if (IS_ERR(plane_state)) {
+   ret = PTR_ERR(plane_state);
+   goto out_state;
+   }
+
+   plane_state->rotation = DRM_MODE_ROTATE_0;
+
+   plane->old_fb = plane->fb;
+   plane_mask |= 1 << drm_plane_index(plane);
+
+   /* disable non-primary: */
+   if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+   continue;
+
+   ret = drm_atomic_disable_plane(plane, plane_state);
+   if (ret != 0)
+   goto out_state;
+   }
+
+   drm_client_display_for_each_modeset(mode_set, display) {
+   struct drm_plane *primary = mode_set->crtc->primary;
+   unsigned int rotation;
+
+   if (drm_client_display_panel_rotation(mode_set->connectors[0], 
primary, )) {
+   /* Cannot fail as we've already gotten the plane state 
above */
+   plane_state = drm_atomic_get_new_plane_state(state, 
primary);
+   plane_state->rotation = rotation;
+   }
+
+   ret = drm_atomic_set_config(mode_set, state);
+   if (ret != 0)
+   goto out_state;
+
+   /*
+* drm_atomic_set_config() sets active when a
+* mode is set, unconditionally clear it if we force DPMS off
+*/
+   if (!active) {
+   struct drm_crtc *crtc = mode_set->crtc;
+   struct drm_crtc_state *crtc_state = 
drm_atomic_get_new_crtc_state(state, crtc);
+
+   

[RFC v4 16/25] drm: Make ioctls available for in-kernel clients

2018-04-14 Thread Noralf Trønnes
Make ioctl wrappers for functions that will be used by the in-kernel API.
The following functions are touched:
- drm_mode_create_dumb_ioctl()
- drm_mode_destroy_dumb_ioctl()
- drm_mode_addfb2()
- drm_mode_rmfb()
- drm_prime_handle_to_fd_ioctl()

drm_mode_addfb2() also gets the ability to override the debug name.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_crtc_internal.h | 18 ++---
 drivers/gpu/drm/drm_dumb_buffers.c  | 33 
 drivers/gpu/drm/drm_framebuffer.c   | 50 -
 drivers/gpu/drm/drm_internal.h  |  3 +++
 drivers/gpu/drm/drm_ioc32.c |  2 +-
 drivers/gpu/drm/drm_ioctl.c |  4 +--
 drivers/gpu/drm/drm_prime.c | 13 +++---
 7 files changed, 84 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_internal.h 
b/drivers/gpu/drm/drm_crtc_internal.h
index 3c2b82865ad2..8f8886ac0e4d 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -62,6 +62,12 @@ int drm_mode_getresources(struct drm_device *dev,
 
 
 /* drm_dumb_buffers.c */
+int drm_mode_create_dumb(struct drm_device *dev,
+struct drm_mode_create_dumb *args,
+struct drm_file *file_priv);
+int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
+ struct drm_file *file_priv);
+
 /* IOCTLs */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
   void *data, struct drm_file *file_priv);
@@ -163,14 +169,18 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, 
uint32_t src_y,
 const struct drm_framebuffer *fb);
 void drm_fb_release(struct drm_file *file_priv);
 
+int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r,
+   struct drm_file *file_priv, const char *comm);
+int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
+ struct drm_file *file_priv);
 
 /* IOCTL */
 int drm_mode_addfb(struct drm_device *dev,
   void *data, struct drm_file *file_priv);
-int drm_mode_addfb2(struct drm_device *dev,
-   void *data, struct drm_file *file_priv);
-int drm_mode_rmfb(struct drm_device *dev,
- void *data, struct drm_file *file_priv);
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_rmfb_ioctl(struct drm_device *dev,
+   void *data, struct drm_file *file_priv);
 int drm_mode_getfb(struct drm_device *dev,
   void *data, struct drm_file *file_priv);
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
diff --git a/drivers/gpu/drm/drm_dumb_buffers.c 
b/drivers/gpu/drm/drm_dumb_buffers.c
index 39ac15ce4702..eed9687b8698 100644
--- a/drivers/gpu/drm/drm_dumb_buffers.c
+++ b/drivers/gpu/drm/drm_dumb_buffers.c
@@ -53,10 +53,10 @@
  * a hardware-specific ioctl to allocate suitable buffer objects.
  */
 
-int drm_mode_create_dumb_ioctl(struct drm_device *dev,
-  void *data, struct drm_file *file_priv)
+int drm_mode_create_dumb(struct drm_device *dev,
+struct drm_mode_create_dumb *args,
+struct drm_file *file_priv)
 {
-   struct drm_mode_create_dumb *args = data;
u32 cpp, stride, size;
 
if (!dev->driver->dumb_create)
@@ -91,6 +91,12 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
return dev->driver->dumb_create(file_priv, dev, args);
 }
 
+int drm_mode_create_dumb_ioctl(struct drm_device *dev,
+  void *data, struct drm_file *file_priv)
+{
+   return drm_mode_create_dumb(dev, data, file_priv);
+}
+
 /**
  * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage 
buffer
  * @dev: DRM device
@@ -122,17 +128,22 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
   >offset);
 }
 
+int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
+ struct drm_file *file_priv)
+{
+   if (!dev->driver->dumb_create)
+   return -ENOSYS;
+
+   if (dev->driver->dumb_destroy)
+   return dev->driver->dumb_destroy(file_priv, dev, handle);
+   else
+   return drm_gem_dumb_destroy(file_priv, dev, handle);
+}
+
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
 {
struct drm_mode_destroy_dumb *args = data;
 
-   if (!dev->driver->dumb_create)
-   return -ENOSYS;
-
-   if (dev->driver->dumb_destroy)
-   return dev->driver->dumb_destroy(file_priv, dev, args->handle);
-   else
-   return drm_gem_dumb_destroy(file_priv, dev, args->handle);
+   return drm_mode_destroy_dumb(dev, args->handle, file_priv);
 }
-
diff --git 

[RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-14 Thread Noralf Trønnes
The modesetting code is already present, this adds the rest of the API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c   | 573 +
 drivers/gpu/drm/drm_debugfs.c  |   7 +
 drivers/gpu/drm/drm_drv.c  |  11 +
 drivers/gpu/drm/drm_file.c |   3 +
 drivers/gpu/drm/drm_probe_helper.c |   3 +
 drivers/gpu/drm/drm_sysfs.c|  20 ++
 include/drm/drm_client.h   | 103 +++
 include/drm/drm_device.h   |   4 +
 8 files changed, 724 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index bce1630a0db2..760f1795f812 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,7 +8,9 @@
  * Copyright (c) 2007 Dave Airlie 
  */
 
+#include 
 #include 
+#include 
 #include 
 
 #include 
@@ -17,14 +19,280 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
+#include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
 struct drm_client_display_offset {
int x, y;
 };
 
+static int drm_client_alloc_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+   struct drm_file *file;
+
+   file = drm_file_alloc(dev->primary);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   drm_dev_get(dev);
+
+   mutex_lock(>filelist_mutex);
+   list_add(>lhead, >filelist_internal);
+   mutex_unlock(>filelist_mutex);
+
+   client->file = file;
+
+   return 0;
+}
+
+static void drm_client_free_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+
+   mutex_lock(>filelist_mutex);
+   list_del(>file->lhead);
+   mutex_unlock(>filelist_mutex);
+
+   drm_file_free(client->file);
+   drm_dev_put(dev);
+}
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs)
+{
+   struct drm_client_dev *client;
+   int ret;
+
+   if (WARN_ON(!funcs->name))
+   return ERR_PTR(-EINVAL);
+
+   client = kzalloc(sizeof(*client), GFP_KERNEL);
+   if (!client)
+   return ERR_PTR(-ENOMEM);
+
+   client->dev = dev;
+   client->funcs = funcs;
+
+   ret = drm_client_alloc_file(client);
+   if (ret) {
+   kfree(client);
+   return ERR_PTR(ret);
+   }
+
+   mutex_lock(>clientlist_mutex);
+   list_add(>list, >clientlist);
+   mutex_unlock(>clientlist_mutex);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new);
+
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs 
*funcs)
+{
+   struct drm_client_dev *client;
+   struct drm_minor *minor;
+
+   minor = drm_minor_acquire(dev_id);
+   if (IS_ERR(minor))
+   return ERR_CAST(minor);
+
+   client = drm_client_new(minor->dev, funcs);
+
+   drm_minor_release(minor);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new_from_id);
+
+/**
+ * drm_client_free - Free DRM client resources
+ * @client: DRM client
+ *
+ * This is called automatically on client removal unless the client returns
+ * non-zero in the _client_funcs->remove callback. The fbdev client does
+ * this when it can't close _file because userspace has an open fd.
+ *
+ * Note:
+ * If the client can't release it's resources on remove, it needs to hold a
+ * reference on the driver module to prevent the code from going away.
+ */
+void drm_client_free(struct drm_client_dev *client)
+{
+   DRM_DEV_DEBUG_KMS(client->dev->dev, "%s\n", client->funcs->name);
+   drm_client_free_file(client);
+   kfree(client);
+}
+EXPORT_SYMBOL(drm_client_free);
+
+static void drm_client_remove_locked(struct drm_client_dev *client)
+{
+   list_del(>list);
+
+   if (!client->funcs->remove || !client->funcs->remove(client))
+   drm_client_free(client);
+}
+
+static void drm_client_remove_safe(struct drm_device *dev,
+  struct drm_client_dev *client)
+{
+   struct drm_client_dev *iter;
+
+   mutex_lock(>clientlist_mutex);
+   list_for_each_entry(iter, >clientlist, list) {
+   if (iter == client) {
+   drm_client_remove_locked(client);
+   break;
+   }
+   }
+   mutex_unlock(>clientlist_mutex);
+}
+
+/**
+ * drm_client_remove - Remove client
+ * @client: Client
+ *
+ * Remove a client.
+ */
+void drm_client_remove(struct drm_client_dev *client)
+{
+   struct drm_device *dev;
+
+   if (!client)
+   return;
+
+   dev = client->dev;
+   drm_dev_get(dev);
+   drm_client_remove_safe(dev, client);
+   drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_client_remove);
+
+struct drm_client_remove_defer {
+   struct list_head list;
+   struct drm_device *dev;
+   struct drm_client_dev *client;
+};
+
+static LIST_HEAD(drm_client_remove_defer_list);

[RFC v4 17/25] drm/client: Bail out if there's a DRM master

2018-04-14 Thread Noralf Trønnes
If there's a DRM master, return -EBUSY.
Block userspace from becoming master by taking the master lock while
the client is setting the mode.

Suggested-by: Daniel Vetter 
Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_auth.c  | 33 +
 drivers/gpu/drm/drm_client.c| 34 +-
 drivers/gpu/drm/drm_fb_helper.c |  8 
 drivers/gpu/drm/drm_internal.h  |  2 ++
 include/drm/drm_client.h|  4 ++--
 5 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index d9c0f7573905..d656d0d93da3 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -366,3 +366,36 @@ void drm_master_put(struct drm_master **master)
*master = NULL;
 }
 EXPORT_SYMBOL(drm_master_put);
+
+/**
+ * drm_master_block - Block DRM master operations
+ * @dev: DRM device
+ *
+ * This function checks if there is a master on @dev. If there is no master it
+ * blocks anyone from becoming master. In-kernel clients can use this to know
+ * when they can act as master. Use drm_master_unblock() to unblock.
+ *
+ * Returns:
+ * True if there is no master, false otherwise.
+ */
+bool drm_master_block(struct drm_device *dev)
+{
+   mutex_lock(>master_mutex);
+   if (dev->master) {
+   mutex_unlock(>master_mutex);
+   return false;
+   }
+
+   return true;
+}
+
+/**
+ * drm_master_unblock - Unblock DRM master operations
+ * @dev: DRM device
+ *
+ * Unblock and allow userspace to become master.
+ */
+void drm_master_unblock(struct drm_device *dev)
+{
+   mutex_unlock(>master_mutex);
+}
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 27818a467b09..764c556630b8 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -18,6 +18,8 @@
 #include 
 #include 
 
+#include "drm_internal.h"
+
 struct drm_client_display_offset {
int x, y;
 };
@@ -313,18 +315,30 @@ static int drm_client_display_restore_legacy(struct 
drm_client_display *display)
 /**
  * drm_client_display_restore() - Restore client display
  * @display: Client display
+ * @force: If true, restore even if there's a DRM master
  *
  * Restore client display using the current modeset configuration.
  *
  * Return:
  * Zero on succes or negative error code on failure.
  */
-int drm_client_display_restore(struct drm_client_display *display)
+int drm_client_display_restore(struct drm_client_display *display, bool force)
 {
-   if (drm_drv_uses_atomic_modeset(display->dev))
-   return drm_client_display_restore_atomic(display, true);
+   struct drm_device *dev = display->dev;
+   int ret;
+
+   if (!force && !drm_master_block(dev))
+   return -EBUSY;
+
+   if (drm_drv_uses_atomic_modeset(dev))
+   ret = drm_client_display_restore_atomic(display, true);
else
-   return drm_client_display_restore_legacy(display);
+   ret = drm_client_display_restore_legacy(display);
+
+   if (!force)
+   drm_master_unblock(dev);
+
+   return ret;
 }
 EXPORT_SYMBOL(drm_client_display_restore);
 
@@ -354,13 +368,23 @@ static void drm_client_display_dpms_legacy(struct 
drm_client_display *display, i
  * drm_client_display_dpms() - Set display DPMS mode
  * @display: Client display
  * @mode: DPMS mode
+ *
+ * Returns:
+ * Zero on success, -EBUSY if there's a DRM master.
  */
-void drm_client_display_dpms(struct drm_client_display *display, int mode)
+int drm_client_display_dpms(struct drm_client_display *display, int mode)
 {
+   if (!drm_master_block(display->dev))
+   return -EBUSY;
+
if (drm_drv_uses_atomic_modeset(display->dev))
drm_client_display_restore_atomic(display, mode == 
DRM_MODE_DPMS_ON);
else
drm_client_display_dpms_legacy(display, mode);
+
+   drm_master_unblock(display->dev);
+
+   return 0;
 }
 EXPORT_SYMBOL(drm_client_display_dpms);
 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 01d8840930a3..98e5bc92c9f2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -181,7 +181,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct 
drm_fb_helper *fb_helper)
return 0;
 
mutex_lock(_helper->lock);
-   ret = drm_client_display_restore(fb_helper->display);
+   ret = drm_client_display_restore(fb_helper->display, false);
 
do_delayed = fb_helper->delayed_hotplug;
if (do_delayed)
@@ -243,7 +243,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
continue;
 
mutex_lock(>lock);
-   ret = drm_client_display_restore(helper->display);
+   ret = drm_client_display_restore(helper->display, true);
if (ret)

[RFC v4 05/25] drm/fb-helper: dpms_legacy(): Only set on connectors in use

2018-04-14 Thread Noralf Trønnes
For each enabled crtc the functions sets dpms on all registered connectors.
Limit this to only doing it once and on the connectors actually in use.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 06e94de6452a..d0936671a9a6 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -583,20 +583,19 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op 
= { };
 static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 {
struct drm_device *dev = fb_helper->dev;
-   struct drm_crtc *crtc;
struct drm_connector *connector;
+   struct drm_mode_set *modeset;
int i, j;
 
drm_modeset_lock_all(dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
-   crtc = fb_helper->crtc_info[i].mode_set.crtc;
+   modeset = _helper->crtc_info[i].mode_set;
 
-   if (!crtc->enabled)
+   if (!modeset->crtc->enabled)
continue;
 
-   /* Walk the connectors & encoders on this fb turning them 
on/off */
-   drm_fb_helper_for_each_connector(fb_helper, j) {
-   connector = fb_helper->connector_info[j]->connector;
+   for (j = 0; j < modeset->num_connectors; j++) {
+   connector = modeset->connectors[j];
connector->funcs->dpms(connector, dpms_mode);
drm_object_property_set_value(>base,
dev->mode_config.dpms_property, dpms_mode);
-- 
2.15.1

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


[RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()

2018-04-14 Thread Noralf Trønnes
Prepare for moving drm_fb_helper modesetting code to drm_client.
drm_client will be linked to drm.ko, so move
__drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
out of drm_kms_helper.ko.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_atomic.c| 168 
 drivers/gpu/drm/drm_atomic_helper.c | 168 +---
 drivers/gpu/drm/drm_fb_helper.c |   8 +-
 include/drm/drm_atomic.h|   5 ++
 include/drm/drm_atomic_helper.h |   4 -
 5 files changed, 179 insertions(+), 174 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 7d25c42f22db..1fb602b6c8b1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -2060,6 +2060,174 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_clean_old_fb);
 
+/* just used from drm_client and atomic-helper: */
+int drm_atomic_disable_plane(struct drm_plane *plane,
+struct drm_plane_state *plane_state)
+{
+   int ret;
+
+   ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+   if (ret != 0)
+   return ret;
+
+   drm_atomic_set_fb_for_plane(plane_state, NULL);
+   plane_state->crtc_x = 0;
+   plane_state->crtc_y = 0;
+   plane_state->crtc_w = 0;
+   plane_state->crtc_h = 0;
+   plane_state->src_x = 0;
+   plane_state->src_y = 0;
+   plane_state->src_w = 0;
+   plane_state->src_h = 0;
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_atomic_disable_plane);
+
+static int update_output_state(struct drm_atomic_state *state,
+  struct drm_mode_set *set)
+{
+   struct drm_device *dev = set->crtc->dev;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+   struct drm_connector *connector;
+   struct drm_connector_state *new_conn_state;
+   int ret, i;
+
+   ret = drm_modeset_lock(>mode_config.connection_mutex,
+  state->acquire_ctx);
+   if (ret)
+   return ret;
+
+   /* First disable all connectors on the target crtc. */
+   ret = drm_atomic_add_affected_connectors(state, set->crtc);
+   if (ret)
+   return ret;
+
+   for_each_new_connector_in_state(state, connector, new_conn_state, i) {
+   if (new_conn_state->crtc == set->crtc) {
+   ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+   NULL);
+   if (ret)
+   return ret;
+
+   /* Make sure legacy setCrtc always re-trains */
+   new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
+   }
+   }
+
+   /* Then set all connectors from set->connectors on the target crtc */
+   for (i = 0; i < set->num_connectors; i++) {
+   new_conn_state = drm_atomic_get_connector_state(state,
+   set->connectors[i]);
+   if (IS_ERR(new_conn_state))
+   return PTR_ERR(new_conn_state);
+
+   ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+   set->crtc);
+   if (ret)
+   return ret;
+   }
+
+   for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+   /*
+* Don't update ->enable for the CRTC in the set_config request,
+* since a mismatch would indicate a bug in the upper layers.
+* The actual modeset code later on will catch any
+* inconsistencies here.
+*/
+   if (crtc == set->crtc)
+   continue;
+
+   if (!new_crtc_state->connector_mask) {
+   ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
+   NULL);
+   if (ret < 0)
+   return ret;
+
+   new_crtc_state->active = false;
+   }
+   }
+
+   return 0;
+}
+
+/* just used from drm_client and atomic-helper: */
+int drm_atomic_set_config(struct drm_mode_set *set,
+ struct drm_atomic_state *state)
+{
+   struct drm_crtc_state *crtc_state;
+   struct drm_plane_state *primary_state;
+   struct drm_crtc *crtc = set->crtc;
+   int hdisplay, vdisplay;
+   int ret;
+
+   crtc_state = drm_atomic_get_crtc_state(state, crtc);
+   if (IS_ERR(crtc_state))
+   return PTR_ERR(crtc_state);
+
+   primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+   if (IS_ERR(primary_state))
+   return PTR_ERR(primary_state);
+
+   if (!set->mode) {
+  

[RFC v4 18/25] drm/client: Make the display modes available to clients

2018-04-14 Thread Noralf Trønnes
Give clients easy access to the display modes.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c | 159 +--
 include/drm/drm_client.h |  25 +++
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 764c556630b8..bce1630a0db2 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,6 +8,7 @@
  * Copyright (c) 2007 Dave Airlie 
  */
 
+#include 
 #include 
 
 #include 
@@ -54,6 +55,7 @@ struct drm_client_display *drm_client_display_create(struct 
drm_device *dev)
}
 
display->dev = dev;
+   INIT_LIST_HEAD(>modes);
display->modeset_count = num_crtc;
 
drm_for_each_crtc(crtc, dev)
@@ -84,12 +86,16 @@ EXPORT_SYMBOL(drm_client_display_create);
  */
 void drm_client_display_free(struct drm_client_display *display)
 {
+   struct drm_display_mode *mode, *tmp;
struct drm_mode_set *modeset;
unsigned int i;
 
if (!display)
return;
 
+   list_for_each_entry_safe(mode, tmp, >modes, head)
+   drm_mode_destroy(display->dev, mode);
+
drm_client_display_for_each_modeset(modeset, display) {
if (modeset->mode)
drm_mode_destroy(display->dev, modeset->mode);
@@ -670,22 +676,70 @@ static int drm_pick_crtcs(struct drm_client_display 
*display,
return best_score;
 }
 
-/**
- * drm_client_find_display() - Find display
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function returns a display the client can use if available.
- *
- * Free resources by calling drm_client_display_free().
- *
- * Returns:
- * A _client_display on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_client_display *
-drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned 
int height)
+/* Give the client a static list of display modes */
+static int drm_client_display_copy_modes(struct drm_client_display *display)
+{
+   int hdisplay = 0, vdisplay = 0, vrefresh;
+   struct drm_device *dev = display->dev;
+   struct drm_display_mode *mode, *copy;
+   struct drm_connector *connector;
+   struct drm_mode_set *modeset;
+   unsigned int count = 0;
+
+   drm_client_display_for_each_modeset(modeset, display) {
+   if (!modeset->num_connectors || !modeset->mode)
+   continue;
+
+   connector = modeset->connectors[0];
+   mode = modeset->mode;
+   count++;
+
+   if (modeset->num_connectors == 2) {
+   /* Cloned output */
+   copy = drm_mode_duplicate(dev, modeset->mode);
+   if (!copy)
+   return -ENOMEM;
+   list_add_tail(>head, >modes);
+   display->mode = copy;
+
+   return 0;
+   }
+
+   if (!modeset->y)
+   hdisplay += modeset->mode->hdisplay;
+   if (!modeset->x)
+   vdisplay += modeset->mode->vdisplay;
+   vrefresh = modeset->mode->vrefresh;
+   }
+
+   if (!count)
+   return 0;
+
+   if (count == 1) {
+   struct drm_display_mode *iter;
+
+   list_for_each_entry(iter, >modes, head) {
+   copy = drm_mode_duplicate(dev, iter);
+   if (!copy)
+   return -ENOMEM;
+   list_add_tail(>head, >modes);
+   if (!display->mode && drm_mode_equal(iter, mode))
+   display->mode = copy;
+   }
+   } else {
+   /* Combined tile mode. Only the default one for now */
+   copy = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, 
false, false);
+   if (!copy)
+   return -ENOMEM;
+   list_add_tail(>head, >modes);
+   display->mode = copy;
+   }
+
+   return 0;
+}
+
+static struct drm_client_display *
+drm_client_find_display_default(struct drm_device *dev, unsigned int width, 
unsigned int height)
 {
struct drm_client_display_offset *offsets;
struct drm_client_display *display;
@@ -695,25 +749,6 @@ drm_client_find_display(struct drm_device *dev, unsigned 
int width, unsigned int
int i, connector_count;
bool *enabled;
 
-   DRM_DEBUG_KMS("\n");
-
-   if (!width)
-   width = dev->mode_config.max_width;
-   if (!height)
-   height = dev->mode_config.max_height;
-
-   mutex_lock(>mode_config.mutex);
-   if (!drm_client_probe_connector_modes(dev, width, height))
-   

[RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client

2018-04-14 Thread Noralf Trønnes
Call the function drm_client_find_display().
No functional change apart from making width/height arguments optional.
Some function name/signature changes and whitespace adjustments.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c| 399 
 drivers/gpu/drm/drm_fb_helper.c | 371 +
 include/drm/drm_client.h|   2 +
 include/drm/drm_fb_helper.h |   4 -
 4 files changed, 403 insertions(+), 373 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index c85c13568cf9..27818a467b09 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -18,6 +18,10 @@
 #include 
 #include 
 
+struct drm_client_display_offset {
+   int x, y;
+};
+
 /**
  * drm_client_display_create() - Create display structure
  * @dev: DRM device
@@ -359,3 +363,398 @@ void drm_client_display_dpms(struct drm_client_display 
*display, int mode)
drm_client_display_dpms_legacy(display, mode);
 }
 EXPORT_SYMBOL(drm_client_display_dpms);
+
+static int drm_client_probe_connector_modes(struct drm_device *dev,
+   u32 max_width, u32 max_height)
+{
+   struct drm_connector_list_iter conn_iter;
+   struct drm_connector *connector;
+   int count = 0;
+
+   drm_connector_list_iter_begin(dev, _iter);
+   drm_for_each_connector_iter(connector, _iter) {
+   count += connector->funcs->fill_modes(connector, max_width, 
max_height);
+   }
+   drm_connector_list_iter_end(_iter);
+
+   return count;
+}
+
+static bool drm_target_cloned(struct drm_device *dev,
+ struct drm_connector **connectors,
+ unsigned int connector_count,
+ struct drm_display_mode **modes,
+ struct drm_client_display_offset *offsets,
+ bool *enabled, int width, int height)
+{
+   int count, i, j;
+   bool can_clone = false;
+   struct drm_display_mode *dmt_mode, *mode;
+
+   /* only contemplate cloning in the single crtc case */
+   if (dev->mode_config.num_crtc > 1)
+   return false;
+
+   count = 0;
+   for (i = 0; i < connector_count; i++) {
+   if (enabled[i])
+   count++;
+   }
+
+   /* only contemplate cloning if more than one connector is enabled */
+   if (count <= 1)
+   return false;
+
+   /* check the command line or if nothing common pick 1024x768 */
+   can_clone = true;
+   for (i = 0; i < connector_count; i++) {
+   if (!enabled[i])
+   continue;
+   modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
+   if (!modes[i]) {
+   can_clone = false;
+   break;
+   }
+   for (j = 0; j < i; j++) {
+   if (!enabled[j])
+   continue;
+   if (!drm_mode_equal(modes[j], modes[i]))
+   can_clone = false;
+   }
+   }
+
+   if (can_clone) {
+   DRM_DEBUG_KMS("can clone using command line\n");
+   return true;
+   }
+
+   /* try and find a 1024x768 mode on each connector */
+   can_clone = true;
+   dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
+
+   for (i = 0; i < connector_count; i++) {
+   if (!enabled[i])
+   continue;
+
+   list_for_each_entry(mode, [i]->modes, head) {
+   if (drm_mode_equal(mode, dmt_mode))
+   modes[i] = mode;
+   }
+   if (!modes[i])
+   can_clone = false;
+   }
+
+   if (can_clone) {
+   DRM_DEBUG_KMS("can clone using 1024x768\n");
+   return true;
+   }
+   DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
+
+   return false;
+}
+
+static void drm_get_tile_offsets(struct drm_connector **connectors,
+unsigned int connector_count,
+struct drm_display_mode **modes,
+struct drm_client_display_offset *offsets,
+int idx,
+int h_idx, int v_idx)
+{
+   int i;
+   int hoffset = 0, voffset = 0;
+
+   for (i = 0; i < connector_count; i++) {
+   struct drm_connector *connector = connectors[i];
+
+   if (!connector->has_tile)
+   continue;
+
+   if (!modes[i] && (h_idx || v_idx)) {
+   DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
+ connector->base.id);
+   

[RFC v4 10/25] drm/connector: Add drm_connector_has_preferred_mode/pick_cmdline_mode()

2018-04-14 Thread Noralf Trønnes
Move them over from drm_fb_helper since they are connector functions.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_connector.c| 94 ++
 drivers/gpu/drm/drm_fb_helper.c| 75 ++
 drivers/gpu/drm/i915/intel_fbdev.c |  7 +--
 include/drm/drm_connector.h|  6 +++
 include/drm/drm_fb_helper.h| 19 
 5 files changed, 108 insertions(+), 93 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b3cde897cd80..b9eb143d70fc 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1760,3 +1760,97 @@ struct drm_tile_group *drm_mode_create_tile_group(struct 
drm_device *dev,
return tg;
 }
 EXPORT_SYMBOL(drm_mode_create_tile_group);
+
+/**
+ * drm_connector_has_preferred_mode() - Lookup preferred display mode
+ * @connector: DRM connector
+ * @width: Max width
+ * @height: Max height
+ *
+ * Look for a preferred display mode within the bounds of @width and @height
+ * (inclusive).
+ *
+ * Returns:
+ * A _display_mode or NULL.
+ */
+struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector,
+int width, int height)
+{
+   struct drm_display_mode *mode;
+
+   list_for_each_entry(mode, >modes, head) {
+   if (mode->hdisplay > width || mode->vdisplay > height)
+   continue;
+   if (mode->type & DRM_MODE_TYPE_PREFERRED)
+   return mode;
+   }
+
+   return NULL;
+}
+EXPORT_SYMBOL(drm_connector_has_preferred_mode);
+
+/**
+ * drm_connector_pick_cmdline_mode() - Get commandline display mode
+ * @connector: DRM connector
+ *
+ * Return the display mode specified on the kernel commandline or NULL if not
+ * specified.
+ *
+ * Returns:
+ * A _display_mode or NULL.
+ */
+struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
+{
+   struct drm_cmdline_mode *cmdline_mode;
+   struct drm_display_mode *mode;
+   bool prefer_non_interlace;
+
+   cmdline_mode = >cmdline_mode;
+   if (!cmdline_mode->specified)
+   return NULL;
+
+   /* attempt to find a matching mode in the list of modes
+*  we have gotten so far, if not add a CVT mode that conforms
+*/
+   if (cmdline_mode->rb || cmdline_mode->margins)
+   goto create_mode;
+
+   prefer_non_interlace = !cmdline_mode->interlace;
+again:
+   list_for_each_entry(mode, >modes, head) {
+   /* check width/height */
+   if (mode->hdisplay != cmdline_mode->xres ||
+   mode->vdisplay != cmdline_mode->yres)
+   continue;
+
+   if (cmdline_mode->refresh_specified) {
+   if (mode->vrefresh != cmdline_mode->refresh)
+   continue;
+   }
+
+   if (cmdline_mode->interlace) {
+   if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
+   continue;
+   } else if (prefer_non_interlace) {
+   if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+   continue;
+   }
+
+   return mode;
+   }
+
+   if (prefer_non_interlace) {
+   prefer_non_interlace = false;
+   goto again;
+   }
+
+create_mode:
+   mode = drm_mode_create_from_cmdline_mode(connector->dev,
+cmdline_mode);
+   list_add(>head, >modes);
+
+   return mode;
+}
+EXPORT_SYMBOL(drm_connector_pick_cmdline_mode);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 785a2f5d2647..b992f59dad30 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1774,78 +1774,11 @@ static int drm_fb_helper_probe_connector_modes(struct 
drm_fb_helper *fb_helper,
return count;
 }
 
-struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector 
*fb_connector, int width, int height)
-{
-   struct drm_display_mode *mode;
-
-   list_for_each_entry(mode, _connector->connector->modes, head) {
-   if (mode->hdisplay > width ||
-   mode->vdisplay > height)
-   continue;
-   if (mode->type & DRM_MODE_TYPE_PREFERRED)
-   return mode;
-   }
-   return NULL;
-}
-EXPORT_SYMBOL(drm_has_preferred_mode);
-
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
return fb_connector->connector->cmdline_mode.specified;
 }
 
-struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector 
*fb_helper_conn)
-{
-   struct drm_cmdline_mode *cmdline_mode;
-   struct drm_display_mode *mode;
-   bool prefer_non_interlace;
-
-   cmdline_mode = 

[RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector

2018-04-14 Thread Noralf Trønnes
No need to maintain a list of registered connectors. Just use the
connector iterator.

TODO: Remove:
- drm_fb_helper_add_one_connector()
- drm_fb_helper_single_add_all_connectors()
- drm_fb_helper_remove_one_connector()

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 359 ++--
 include/drm/drm_fb_helper.h |  13 --
 2 files changed, 86 insertions(+), 286 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index ce38eadcb346..6ee61f195321 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -112,59 +112,10 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()).
  */
 
-#define drm_fb_helper_for_each_connector(fbh, i__) \
-   for (({ lockdep_assert_held(&(fbh)->lock); }), \
-i__ = 0; i__ < (fbh)->connector_count; i__++)
-
-static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-struct drm_connector *connector)
-{
-   struct drm_fb_helper_connector *fb_conn;
-   struct drm_fb_helper_connector **temp;
-   unsigned int count;
-
-   if (!drm_fbdev_emulation)
-   return 0;
-
-   lockdep_assert_held(_helper->lock);
-
-   count = fb_helper->connector_count + 1;
-
-   if (count > fb_helper->connector_info_alloc_count) {
-   size_t size = count * sizeof(fb_conn);
-
-   temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL);
-   if (!temp)
-   return -ENOMEM;
-
-   fb_helper->connector_info_alloc_count = count;
-   fb_helper->connector_info = temp;
-   }
-
-   fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL);
-   if (!fb_conn)
-   return -ENOMEM;
-
-   drm_connector_get(connector);
-   fb_conn->connector = connector;
-   fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
-
-   return 0;
-}
-
 int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
struct drm_connector *connector)
 {
-   int err;
-
-   if (!fb_helper)
-   return 0;
-
-   mutex_lock(_helper->lock);
-   err = __drm_fb_helper_add_one_connector(fb_helper, connector);
-   mutex_unlock(_helper->lock);
-
-   return err;
+   return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
 
@@ -184,87 +135,14 @@ EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
  */
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
 {
-   struct drm_device *dev;
-   struct drm_connector *connector;
-   struct drm_connector_list_iter conn_iter;
-   int i, ret = 0;
-
-   if (!drm_fbdev_emulation || !fb_helper)
-   return 0;
-
-   dev = fb_helper->dev;
-
-   mutex_lock(_helper->lock);
-   drm_connector_list_iter_begin(dev, _iter);
-   drm_for_each_connector_iter(connector, _iter) {
-   ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
-   if (ret)
-   goto fail;
-   }
-   goto out;
-
-fail:
-   drm_fb_helper_for_each_connector(fb_helper, i) {
-   struct drm_fb_helper_connector *fb_helper_connector =
-   fb_helper->connector_info[i];
-
-   drm_connector_put(fb_helper_connector->connector);
-
-   kfree(fb_helper_connector);
-   fb_helper->connector_info[i] = NULL;
-   }
-   fb_helper->connector_count = 0;
-out:
-   drm_connector_list_iter_end(_iter);
-   mutex_unlock(_helper->lock);
-
-   return ret;
-}
-EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
-
-static int __drm_fb_helper_remove_one_connector(struct drm_fb_helper 
*fb_helper,
-   struct drm_connector *connector)
-{
-   struct drm_fb_helper_connector *fb_helper_connector;
-   int i, j;
-
-   if (!drm_fbdev_emulation)
-   return 0;
-
-   lockdep_assert_held(_helper->lock);
-
-   drm_fb_helper_for_each_connector(fb_helper, i) {
-   if (fb_helper->connector_info[i]->connector == connector)
-   break;
-   }
-
-   if (i == fb_helper->connector_count)
-   return -EINVAL;
-   fb_helper_connector = fb_helper->connector_info[i];
-   drm_connector_put(fb_helper_connector->connector);
-
-   for (j = i + 1; j < fb_helper->connector_count; j++)
-   fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
-
-   fb_helper->connector_count--;
-   kfree(fb_helper_connector);
-
return 0;
 }
+EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
   struct drm_connector 

[RFC v4 11/25] drm/connector: Add connector array functions

2018-04-14 Thread Noralf Trønnes
Add functions to deal with the registred connectors as an array:
- drm_connector_get_all()
- drm_connector_put_all()

And to get the enabled status of those connectors:
drm_connector_get_enabled_status()

This is prep work to remove struct drm_fb_helper_connector.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_connector.c | 105 
 include/drm/drm_connector.h |   5 ++
 2 files changed, 110 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b9eb143d70fc..25c333c05a4e 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1854,3 +1854,108 @@ drm_connector_pick_cmdline_mode(struct drm_connector 
*connector)
return mode;
 }
 EXPORT_SYMBOL(drm_connector_pick_cmdline_mode);
+
+/**
+ * drm_connector_get_all - Get all connectors into an array
+ * @dev: DRM device
+ * @connectors: Returned connector array
+ *
+ * This function iterates through all registered connectors and adds them to an
+ * array allocated by this function. A ref is taken on the connectors.
+ *
+ * Use drm_connector_put_all() to drop refs and free the array.
+ *
+ * Returns:
+ * Number of connectors or -ENOMEM on failure.
+ */
+int drm_connector_get_all(struct drm_device *dev, struct drm_connector 
***connectors)
+{
+   struct drm_connector *connector, **temp, **conns = NULL;
+   struct drm_connector_list_iter conn_iter;
+   int connector_count = 0;
+
+   drm_connector_list_iter_begin(dev, _iter);
+   drm_for_each_connector_iter(connector, _iter) {
+   temp = krealloc(conns, (connector_count + 1) * sizeof(*conns), 
GFP_KERNEL);
+   if (!temp)
+   goto err_put_free;
+
+   conns = temp;
+   conns[connector_count++] = connector;
+   drm_connector_get(connector);
+   }
+   drm_connector_list_iter_end(_iter);
+
+   *connectors = conns;
+
+   return connector_count;
+
+err_put_free:
+   drm_connector_list_iter_end(_iter);
+   drm_connector_put_all(conns, connector_count);
+
+   return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_connector_get_all);
+
+/**
+ * drm_connector_put_all - Put and free connector array
+ * @connectors: Array of connectors
+ * @connector_count: Number of connectors in the array (can be negative or 
zero)
+ *
+ * This function drops the ref on the connectors an frees the array.
+ */
+void drm_connector_put_all(struct drm_connector **connectors, int 
connector_count)
+{
+   int i;
+
+   if (connector_count < 1)
+   return;
+
+   for (i = 0; i < connector_count; i++)
+   drm_connector_put(connectors[i]);
+   kfree(connectors);
+}
+EXPORT_SYMBOL(drm_connector_put_all);
+
+/**
+ * drm_connector_get_enabled_status - Get enabled status on connectors
+ * @connectors: Array of connectors
+ * @connector_count: Number of connectors in the array
+ *
+ * This loops over the connector array and sets enabled if connector status is
+ * _connected_. If no connectors are connected, a new pass is done and
+ * connectors that are not _disconnected_ are set enabled.
+ *
+ * The caller is responsible for freeing the array using kfree().
+ *
+ * Returns:
+ * A boolean array of connector enabled statuses or NULL on allocation failure.
+ */
+bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
+  unsigned int connector_count)
+{
+   bool *enabled, any_enabled = false;
+   unsigned int i;
+
+   enabled = kcalloc(connector_count, sizeof(*enabled), GFP_KERNEL);
+   if (!enabled)
+   return NULL;
+
+   for (i = 0; i < connector_count; i++) {
+   if (connectors[i]->status == connector_status_connected) {
+   enabled[i] = true;
+   any_enabled = true;
+   }
+   }
+
+   if (any_enabled)
+   return enabled;
+
+   for (i = 0; i < connector_count; i++)
+   if (connectors[i]->status != connector_status_disconnected)
+   enabled[i] = true;
+
+   return enabled;
+}
+EXPORT_SYMBOL(drm_connector_get_enabled_status);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 9cb4ca42373c..c3556a5f40c9 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1169,4 +1169,9 @@ drm_connector_has_preferred_mode(struct drm_connector 
*connector,
 struct drm_display_mode *
 drm_connector_pick_cmdline_mode(struct drm_connector *connector);
 
+int drm_connector_get_all(struct drm_device *dev, struct drm_connector 
***connectors);
+void drm_connector_put_all(struct drm_connector **connectors, int 
connector_count);
+bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
+  unsigned int connector_count);
+
 #endif
-- 
2.15.1


[RFC v4 23/25] drm: Add DRM device registered notifier

2018-04-14 Thread Noralf Trønnes
Add a notifier that fires when a new DRM device is registered.
This can be used by the bootsplash client to connect to all devices.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_drv.c | 32 
 include/drm/drm_drv.h |  4 
 2 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 6f21bafb29be..e42ce320ad07 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -79,6 +80,8 @@ static struct dentry *drm_debugfs_root;
 
 DEFINE_STATIC_SRCU(drm_unplug_srcu);
 
+static BLOCKING_NOTIFIER_HEAD(drm_dev_notifier);
+
 /*
  * DRM Minors
  * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
@@ -837,6 +840,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long 
flags)
 dev->dev ? dev_name(dev->dev) : "virtual device",
 dev->primary->index);
 
+   blocking_notifier_call_chain(_dev_notifier, 0, dev);
+
goto out_unlock;
 
 err_minors:
@@ -894,6 +899,33 @@ void drm_dev_unregister(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_dev_unregister);
 
+/**
+ * drm_dev_register_notifier - Register a notifier for new DRM devices
+ * @nb: Notifier block
+ *
+ * Register a notifier that fires when a new _device is registered.
+ *
+ * Note:
+ * Users of this function has to be linked into drm.ko. This is done to make
+ * life simple avoiding tricky race situations.
+ */
+void drm_dev_register_notifier(struct notifier_block *nb)
+{
+   /* Currently this can't fail, but catch it in case this changes */
+   WARN_ON(blocking_notifier_chain_register(_dev_notifier, nb));
+}
+
+/**
+ * drm_dev_unregister_notifier - Unregister DRM device notifier
+ * @nb: Notifier block
+ *
+ * This is a no-op if the notifier isn't registered.
+ */
+void drm_dev_unregister_notifier(struct notifier_block *nb)
+{
+   blocking_notifier_chain_unregister(_dev_notifier, nb);
+}
+
 /**
  * drm_dev_set_unique - Set the unique name of a DRM device
  * @dev: device of which to set the unique name
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 13356e6fd40c..5e6c6ed0d59d 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -40,6 +40,7 @@ struct drm_minor;
 struct dma_buf_attachment;
 struct drm_display_mode;
 struct drm_mode_create_dumb;
+struct notifier_block;
 struct drm_printer;
 
 /* driver capabilities and requirements mask */
@@ -641,6 +642,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
 int drm_dev_register(struct drm_device *dev, unsigned long flags);
 void drm_dev_unregister(struct drm_device *dev);
 
+void drm_dev_register_notifier(struct notifier_block *nb);
+void drm_dev_unregister_notifier(struct notifier_block *nb);
+
 void drm_dev_get(struct drm_device *dev);
 void drm_dev_put(struct drm_device *dev);
 void drm_dev_unref(struct drm_device *dev);
-- 
2.15.1

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


[RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback

2018-04-14 Thread Noralf Trønnes
As part of moving the modesetting code out of drm_fb_helper and into
drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
Replace it with a drm_driver->initial_client_display callback that can
work for all in-kernel clients.

TODO:
- Add a patch that moves the function out of intel_fbdev.c since it's not
  fbdev specific anymore.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c|  19 +--
 drivers/gpu/drm/i915/i915_drv.c|   1 +
 drivers/gpu/drm/i915/intel_drv.h   |  11 
 drivers/gpu/drm/i915/intel_fbdev.c | 113 ++---
 include/drm/drm_drv.h  |  21 +++
 5 files changed, 104 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b992f59dad30..5407bf6dc8c0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2103,6 +2103,20 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
/* prevent concurrent modification of connector_count by hotplug */
lockdep_assert_held(_helper->lock);
 
+   mutex_lock(>mode_config.mutex);
+   if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
+   DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+   if (dev->driver->initial_client_display) {
+   display = dev->driver->initial_client_display(dev, width, 
height);
+   if (display) {
+   drm_client_display_free(fb_helper->display);
+   fb_helper->display = display;
+   mutex_unlock(>mode_config.mutex);
+   return;
+   }
+   }
+
crtcs = kcalloc(fb_helper->connector_count,
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
modes = kcalloc(fb_helper->connector_count,
@@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
if (IS_ERR(display))
goto out;
 
-   mutex_lock(_helper->dev->mode_config.mutex);
-   if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
-   DRM_DEBUG_KMS("No connectors reported connected with modes\n");
drm_enable_connectors(fb_helper, enabled);
 
if (!(fb_helper->funcs->initial_config &&
@@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
 
drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
}
-   mutex_unlock(_helper->dev->mode_config.mutex);
 
/* need to set the modesets up here for use later */
/* fill out the connector<->crtc mappings into the modesets */
@@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
drm_client_display_free(fb_helper->display);
fb_helper->display = display;
 out:
+   mutex_unlock(>mode_config.mutex);
kfree(crtcs);
kfree(modes);
kfree(offsets);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 07c07d55398b..b746c0cbaa4b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
 
.dumb_create = i915_gem_dumb_create,
.dumb_map_offset = i915_gem_mmap_gtt,
+   .initial_client_display = i915_initial_client_display,
.ioctls = i915_ioctls,
.num_ioctls = ARRAY_SIZE(i915_ioctls),
.fops = _driver_fops,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d4368589b355..f77f510617c5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private 
*dev_priv);
 extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool 
synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
 extern void intel_fbdev_restore_mode(struct drm_device *dev);
+struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+   unsigned int height);
 #else
 static inline int intel_fbdev_init(struct drm_device *dev)
 {
@@ -1749,6 +1752,14 @@ static inline void 
intel_fbdev_output_poll_changed(struct drm_device *dev)
 static inline void intel_fbdev_restore_mode(struct drm_device *dev)
 {
 }
+
+static inline struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+   unsigned int height)
+{
+   return NULL;
+}
+
 #endif
 
 /* intel_fbc.c */
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c 
b/drivers/gpu/drm/i915/intel_fbdev.c
index a4ab8575a72e..b7f44c9475a8 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -38,6 +38,7 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
 #include "intel_drv.h"
@@ 

[RFC v4 07/25] drm: Begin an API for in-kernel clients

2018-04-14 Thread Noralf Trønnes
This the beginning of an API for in-kernel clients.
First out is a display representation that will be used by drm_fb_helper
in order to move out its mode setting code.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/Makefile |   2 +-
 drivers/gpu/drm/drm_client.c | 119 +++
 include/drm/drm_client.h |  44 
 3 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_client.c
 create mode 100644 include/drm/drm_client.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9d66657ea117..d25afa136d8f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -18,7 +18,7 @@ drm-y   :=drm_auth.o drm_bufs.o drm_cache.o \
drm_encoder.o drm_mode_object.o drm_property.o \
drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
-   drm_syncobj.o drm_lease.o
+   drm_syncobj.o drm_lease.o drm_client.o
 
 drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
 drm-$(CONFIG_DRM_VM) += drm_vm.o
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
new file mode 100644
index ..7c31a6efb2f4
--- /dev/null
+++ b/drivers/gpu/drm/drm_client.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Noralf Trønnes
+ *
+ * For parts copied from drm_fb_helper:
+ * Copyright (c) 2006-2009 Red Hat Inc.
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie 
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * drm_client_display_create() - Create display structure
+ * @dev: DRM device
+ *
+ * This function creates a display structure for clients backed by an array of
+ * _mode_set, one per CRTC.
+ *
+ * Returns:
+ * A _client_display or an error pointer on allocation failure.
+ */
+struct drm_client_display *drm_client_display_create(struct drm_device *dev)
+{
+   unsigned int num_crtc = dev->mode_config.num_crtc;
+   struct drm_client_display *display;
+   struct drm_mode_set *modeset;
+   struct drm_crtc *crtc;
+   unsigned int i = 0;
+
+   display = kzalloc(sizeof(*display), GFP_KERNEL);
+   if (!display)
+   return ERR_PTR(-ENOMEM);
+
+   /* Add NULL terminating entry to enable index less iteration */
+   display->modesets = kcalloc(num_crtc + 1, sizeof(*display->modesets), 
GFP_KERNEL);
+   if (!display->modesets) {
+   kfree(display);
+   return ERR_PTR(-ENOMEM);
+   }
+
+   display->dev = dev;
+   display->modeset_count = num_crtc;
+
+   drm_for_each_crtc(crtc, dev)
+   display->modesets[i++].crtc = crtc;
+
+   drm_client_display_for_each_modeset(modeset, display) {
+   /* One connector per crtc except for the cloned case */
+   modeset->connectors = kcalloc(2, sizeof(*modeset->connectors), 
GFP_KERNEL);
+   if (!modeset->connectors)
+   goto err_free;
+   }
+
+   return display;
+
+err_free:
+   drm_client_display_free(display);
+
+   return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(drm_client_display_create);
+
+/**
+ * drm_client_display_free() - Free display structure
+ * @display: Client display
+ *
+ * This function frees the structure allocated by drm_client_display_create().
+ * It also destroys display modes and puts connectors.
+ */
+void drm_client_display_free(struct drm_client_display *display)
+{
+   struct drm_mode_set *modeset;
+   unsigned int i;
+
+   if (!display)
+   return;
+
+   drm_client_display_for_each_modeset(modeset, display) {
+   if (modeset->mode)
+   drm_mode_destroy(display->dev, modeset->mode);
+
+   for (i = 0; i < modeset->num_connectors; i++)
+   drm_connector_put(modeset->connectors[i]);
+   kfree(modeset->connectors);
+   }
+   kfree(display->modesets);
+   kfree(display);
+}
+EXPORT_SYMBOL(drm_client_display_free);
+
+/**
+ * drm_client_display_find_modeset() - Find modeset matching a CRTC
+ * @display: Client display
+ * @crtc: CRTC
+ *
+ * This function looks up the @display modeset connected to @crtc.
+ *
+ * Returns:
+ * A _mode_set or NULL.
+ */
+struct drm_mode_set *
+drm_client_display_find_modeset(struct drm_client_display *display, struct 
drm_crtc *crtc)
+{
+   struct drm_mode_set *modeset;
+
+   drm_client_display_for_each_modeset(modeset, display)
+   if (modeset->crtc == crtc)
+   return modeset;
+
+   return NULL;
+}
+EXPORT_SYMBOL(drm_client_display_find_modeset);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
new file mode 100644
index ..b6a057802769
--- /dev/null
+++ b/include/drm/drm_client.h
@@ -0,0 +1,44 @@
+/* 

[RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients

2018-04-14 Thread Noralf Trønnes
Avoid pinning the module when exporting a GEM object as a dmabuf. This
makes it possible to unload drivers that has in-kernel clients using it.
The client is removed on drm_dev_unregister() so no need to pin the driver.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_prime.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index e6052ab2bec4..f9dbe3b9db20 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -567,6 +567,30 @@ struct dma_buf *drm_gem_prime_export(struct drm_device 
*dev,
.flags = flags,
.priv = obj,
};
+   bool is_internal = false;
+   struct drm_file *file;
+
+   mutex_lock(>filelist_mutex);
+   list_for_each_entry(file, >filelist_internal, lhead) {
+   struct drm_gem_object *iter;
+   int id;
+
+   spin_lock(>table_lock);
+   idr_for_each_entry(>object_idr, iter, id) {
+   if (iter == obj) {
+   is_internal = true;
+   break;
+   }
+   }
+   spin_unlock(>table_lock);
+
+   if (is_internal)
+   break;
+   }
+   mutex_unlock(>filelist_mutex);
+
+   if (is_internal)
+   exp_info.owner = NULL;
 
if (dev->driver->gem_prime_res_obj)
exp_info.resv = dev->driver->gem_prime_res_obj(obj);
-- 
2.15.1

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


[RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc

2018-04-14 Thread Noralf Trønnes
The stage is now set for a clean removal of drm_fb_helper_crtc.
struct drm_client_display is doing its job now.

Also remove the drm_fb_helper_funcs->initial_config which has been
superseded by drm_driver->initial_client_display.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 124 +---
 include/drm/drm_fb_helper.h |  31 --
 2 files changed, 26 insertions(+), 129 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5407bf6dc8c0..ce38eadcb346 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -443,24 +443,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_blank);
 
-static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
- struct drm_mode_set *modeset)
-{
-   int i;
-
-   for (i = 0; i < modeset->num_connectors; i++) {
-   drm_connector_put(modeset->connectors[i]);
-   modeset->connectors[i] = NULL;
-   }
-   modeset->num_connectors = 0;
-
-   drm_mode_destroy(helper->dev, modeset->mode);
-   modeset->mode = NULL;
-
-   /* FIXME should hold a ref? */
-   modeset->fb = NULL;
-}
-
 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
 {
int i;
@@ -470,14 +452,6 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper 
*helper)
kfree(helper->connector_info[i]);
}
kfree(helper->connector_info);
-
-   for (i = 0; i < helper->crtc_count; i++) {
-   struct drm_mode_set *modeset = >crtc_info[i].mode_set;
-
-   drm_fb_helper_modeset_release(helper, modeset);
-   kfree(modeset->connectors);
-   }
-   kfree(helper->crtc_info);
 }
 
 static void drm_fb_helper_resume_worker(struct work_struct *work)
@@ -552,48 +526,18 @@ int drm_fb_helper_init(struct drm_device *dev,
   struct drm_fb_helper *fb_helper,
   int max_conn_count)
 {
-   struct drm_crtc *crtc;
-   struct drm_mode_config *config = >mode_config;
-   int i;
-
if (!drm_fbdev_emulation) {
dev->fb_helper = fb_helper;
return 0;
}
 
-   if (!max_conn_count)
-   return -EINVAL;
-
-   fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct 
drm_fb_helper_crtc), GFP_KERNEL);
-   if (!fb_helper->crtc_info)
-   return -ENOMEM;
-
-   fb_helper->crtc_count = config->num_crtc;
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, 
sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-   if (!fb_helper->connector_info) {
-   kfree(fb_helper->crtc_info);
+   if (!fb_helper->connector_info)
return -ENOMEM;
-   }
+
fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
fb_helper->connector_count = 0;
 
-   for (i = 0; i < fb_helper->crtc_count; i++) {
-   fb_helper->crtc_info[i].mode_set.connectors =
-   kcalloc(max_conn_count,
-   sizeof(struct drm_connector *),
-   GFP_KERNEL);
-
-   if (!fb_helper->crtc_info[i].mode_set.connectors)
-   goto out_free;
-   fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-   }
-
-   i = 0;
-   drm_for_each_crtc(crtc, dev) {
-   fb_helper->crtc_info[i].mode_set.crtc = crtc;
-   i++;
-   }
-
fb_helper->display = drm_client_display_create(dev);
if (IS_ERR(fb_helper->display))
goto out_free;
@@ -1830,7 +1774,7 @@ static bool drm_target_cloned(struct drm_fb_helper 
*fb_helper,
struct drm_display_mode *dmt_mode, *mode;
 
/* only contemplate cloning in the single crtc case */
-   if (fb_helper->crtc_count > 1)
+   if (fb_helper->dev->mode_config.num_crtc > 1)
return false;
 
count = 0;
@@ -1997,16 +1941,18 @@ static bool drm_target_preferred(struct drm_fb_helper 
*fb_helper,
 }
 
 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
- struct drm_fb_helper_crtc **best_crtcs,
+ struct drm_crtc **best_crtcs,
  struct drm_display_mode **modes,
  int n, int width, int height)
 {
-   int c, o;
+   struct drm_client_display *display = fb_helper->display;
+   struct drm_device *dev = display->dev;
+   int o, my_score, best_score, score;
struct drm_connector *connector;
const struct drm_connector_helper_funcs *connector_funcs;
+   struct drm_mode_set *modeset;
struct drm_encoder *encoder;
-   int my_score, best_score, score;
-   struct drm_fb_helper_crtc **crtcs, *crtc;
+   struct 

[RFC v4 24/25] drm/client: Hack: Add bootsplash

2018-04-14 Thread Noralf Trønnes
A hack to test the client API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/Kconfig |   2 +
 drivers/gpu/drm/Makefile|   1 +
 drivers/gpu/drm/client/Kconfig  |   9 ++
 drivers/gpu/drm/client/drm_bootsplash.c | 248 
 drivers/gpu/drm/client/internal.h   |  19 +++
 drivers/gpu/drm/drm_client.c|   4 +
 6 files changed, 283 insertions(+)
 create mode 100644 drivers/gpu/drm/client/Kconfig
 create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
 create mode 100644 drivers/gpu/drm/client/internal.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 757825ac60df..1328202ce17d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -154,6 +154,8 @@ config DRM_SCHED
tristate
depends on DRM
 
+source "drivers/gpu/drm/client/Kconfig"
+
 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 d25afa136d8f..388527093f80 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -30,6 +30,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.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_CLIENT_BOOTSPLASH) += client/drm_bootsplash.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/client/Kconfig b/drivers/gpu/drm/client/Kconfig
new file mode 100644
index ..6b01f2e51fb3
--- /dev/null
+++ b/drivers/gpu/drm/client/Kconfig
@@ -0,0 +1,9 @@
+menu "DRM Clients"
+   depends on DRM
+
+config DRM_CLIENT_BOOTSPLASH
+   bool "DRM Bootsplash"
+   help
+ DRM Bootsplash
+
+endmenu
diff --git a/drivers/gpu/drm/client/drm_bootsplash.c 
b/drivers/gpu/drm/client/drm_bootsplash.c
new file mode 100644
index ..bec3105f9b02
--- /dev/null
+++ b/drivers/gpu/drm/client/drm_bootsplash.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+// drm_lastclose()
+#include 
+#include "drm_internal.h"
+
+static bool drm_bootsplash_enabled = true;
+module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0600);
+MODULE_PARM_DESC(bootsplash_enabled, "Enable bootsplash client 
[default=true]");
+
+struct drm_bootsplash {
+   struct drm_client_dev *client;
+   struct drm_client_display *display;
+   struct drm_client_buffer *buffer[2];
+   struct work_struct worker;
+   bool stop;
+};
+
+static bool drm_bootsplash_key_pressed;
+
+static int drm_bootsplash_keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+   /* Any key is good */
+   drm_bootsplash_key_pressed = true;
+
+   return NOTIFY_OK;
+}
+
+static struct notifier_block drm_bootsplash_keyboard_notifier_block = {
+   .notifier_call = drm_bootsplash_keyboard_notifier_call,
+};
+
+static u32 drm_bootsplash_color_table[3] = {
+   0x00ff, 0xff00, 0x00ff,
+};
+
+/* Draw a box with changing colors */
+static void
+drm_bootsplash_draw(struct drm_client_buffer *buffer, unsigned int sequence)
+{
+   unsigned int x, y;
+   u32 *pix;
+
+   pix = buffer->vaddr;
+   pix += ((buffer->height / 2) - 50) * buffer->width;
+   pix += (buffer->width / 2) - 50;
+
+   for (y = 0; y < 100; y++) {
+   for (x = 0; x < 100; x++)
+   *pix++ = drm_bootsplash_color_table[sequence];
+   pix += buffer->width - 100;
+   }
+}
+
+static void drm_bootsplash_worker(struct work_struct *work)
+{
+   struct drm_bootsplash *splash = container_of(work, struct 
drm_bootsplash, worker);
+   struct drm_device *dev = splash->client->dev;
+   unsigned int i = 0, sequence = 0;
+   struct drm_framebuffer *fb;
+   int ret = 0;
+
+   while (!splash->stop && !drm_bootsplash_key_pressed) {
+   /* Did someone take over, like another in-kernel client, except 
fbdev? */
+   fb = drm_client_display_current_fb(splash->display);
+   if (splash->buffer[i]->fb != fb &&
+   !(dev->fb_helper && dev->fb_helper->fb == fb))
+   break;
+
+   i = !i;
+   drm_bootsplash_draw(splash->buffer[i], sequence++);
+   if (sequence == 3)
+   sequence = 0;
+
+   ret = drm_client_display_commit(splash->display, 
splash->buffer[i]->fb, NULL);
+   /* Is userspace in charge or is the device unplugged? */
+   if (ret == -EBUSY || ret == -ENODEV)
+   break;
+
+   msleep(500);
+ 

[RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation

2018-04-14 Thread Noralf Trønnes
This adds generic fbdev emulation for drivers that supports
dumb buffers which they can export.

All the driver has to do is call drm_fbdev_generic_setup().

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 255 
 include/drm/drm_fb_helper.h |  20 
 2 files changed, 275 insertions(+)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b1124c08b1ed..1954de5b13e0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct 
drm_device *dev)
 }
 EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
 
+static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+   struct drm_fb_helper *fb_helper = info->par;
+
+   return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0);
+}
+
+/*
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
+ * unregister_framebuffer() or fb_release().
+ */
+static void drm_fbdev_fb_destroy(struct fb_info *info)
+{
+   struct drm_fb_helper *fb_helper = info->par;
+   struct fb_ops *fbops = NULL;
+
+   DRM_DEBUG("\n");
+
+   if (fb_helper->fbdev->fbdefio)
+   fbops = fb_helper->fbdev->fbops;
+
+   drm_fb_helper_fini(fb_helper);
+   drm_client_framebuffer_delete(fb_helper->buffer);
+   drm_client_free(fb_helper->client);
+   kfree(fb_helper);
+   kfree(fbops);
+}
+
+static struct fb_ops drm_fbdev_fb_ops = {
+   /*
+* No need to set owner, this module is already pinned by the driver.
+* A reference is taken on the driver module in drm_fb_helper_fb_open()
+* to prevent the driver going away with open fd's.
+*/
+   DRM_FB_HELPER_DEFAULT_OPS,
+   .fb_open= drm_fb_helper_fb_open,
+   .fb_release = drm_fb_helper_fb_release,
+   .fb_destroy = drm_fbdev_fb_destroy,
+   .fb_mmap= drm_fbdev_fb_mmap,
+   .fb_read= drm_fb_helper_sys_read,
+   .fb_write   = drm_fb_helper_sys_write,
+   .fb_fillrect= drm_fb_helper_sys_fillrect,
+   .fb_copyarea= drm_fb_helper_sys_copyarea,
+   .fb_imageblit   = drm_fb_helper_sys_imageblit,
+};
+
+static struct fb_deferred_io drm_fbdev_defio = {
+   .delay  = HZ / 20,
+   .deferred_io= drm_fb_helper_deferred_io,
+};
+
+/* Hack to test tinydrm before converting to vmalloc buffers */
+static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+   fb_deferred_io_mmap(info, vma);
+   vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+   return 0;
+}
+
+static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+  struct drm_fb_helper_surface_size *sizes)
+{
+   struct drm_client_dev *client = fb_helper->client;
+   struct drm_display_mode sizes_mode = {
+   .hdisplay = sizes->surface_width,
+   .vdisplay = sizes->surface_height,
+   };
+   struct drm_client_buffer *buffer;
+   struct drm_framebuffer *fb;
+   struct fb_info *fbi;
+   u32 format;
+   int ret;
+
+   DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+
+   format = drm_mode_legacy_fb_format(sizes->surface_bpp, 
sizes->surface_depth);
+   buffer = drm_client_framebuffer_create(client, _mode, format);
+   if (IS_ERR(buffer))
+   return PTR_ERR(buffer);
+
+   fb_helper->buffer = buffer;
+   fb_helper->fb = buffer->fb;
+   fb = buffer->fb;
+
+   fbi = drm_fb_helper_alloc_fbi(fb_helper);
+   if (IS_ERR(fbi)) {
+   ret = PTR_ERR(fbi);
+   goto err_free_buffer;
+   }
+
+   fbi->par = fb_helper;
+   fbi->fbops = _fbdev_fb_ops;
+   fbi->screen_size = fb->height * fb->pitches[0];
+   fbi->fix.smem_len = fbi->screen_size;
+   fbi->screen_buffer = buffer->vaddr;
+   strcpy(fbi->fix.id, "DRM emulated");
+
+   drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
+   drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, 
sizes->fb_height);
+
+   /*
+* Drivers that set the dirty callback:
+* - Doesn't use defio:
+*   i915, virtio, rockchip
+* - defio with vmalloc buffer blitted on the real one:
+*   vmwgfx
+* - defio is disabled because it doesn't work with shmem:
+*   udl
+* - defio with special dirty callback for fbdev, uses vmalloc for 
fbdev:
+*   qxl
+* - defio with cma buffer, will move to vmalloc buffers:
+*   tinydrm
+

[RFC v4 25/25] drm/client: Hack: Add DRM VT console client

2018-04-14 Thread Noralf Trønnes
A hack to test the client API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/Makefile   |   1 +
 drivers/gpu/drm/client/Kconfig |   5 +
 drivers/gpu/drm/client/Makefile|   3 +
 drivers/gpu/drm/client/drm_vtcon.c | 785 +
 4 files changed, 794 insertions(+)
 create mode 100644 drivers/gpu/drm/client/Makefile
 create mode 100644 drivers/gpu/drm/client/drm_vtcon.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 388527093f80..ea63eb9e93ec 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/
 
 obj-$(CONFIG_DRM)  += drm.o
+obj-y  += client/
 obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
 obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_ARM)  += arm/
diff --git a/drivers/gpu/drm/client/Kconfig b/drivers/gpu/drm/client/Kconfig
index 6b01f2e51fb3..b03f3baf8b3f 100644
--- a/drivers/gpu/drm/client/Kconfig
+++ b/drivers/gpu/drm/client/Kconfig
@@ -6,4 +6,9 @@ config DRM_CLIENT_BOOTSPLASH
help
  DRM Bootsplash
 
+config DRM_CLIENT_VTCON
+   tristate "DRM VT console"
+   help
+ DRM VT console
+
 endmenu
diff --git a/drivers/gpu/drm/client/Makefile b/drivers/gpu/drm/client/Makefile
new file mode 100644
index ..7d39f1bc2b68
--- /dev/null
+++ b/drivers/gpu/drm/client/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DRM_CLIENT_VTCON) += drm_vtcon.o
diff --git a/drivers/gpu/drm/client/drm_vtcon.c 
b/drivers/gpu/drm/client/drm_vtcon.c
new file mode 100644
index ..910b4ec1a686
--- /dev/null
+++ b/drivers/gpu/drm/client/drm_vtcon.c
@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2018 Noralf Trønnes
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* TODO: Scrolling */
+
+/*
+ * The code consists of 3 parts:
+ *
+ * 1. The DRM client
+ *Gets a display, uses the first mode to find a font,
+ *sets the max cols/rows and a matching text buffer.
+ *
+ * 2. The VT console
+ *Writes to the text buffer which consists of CGA colored characters.
+ *Schedules the worker when it needs rendering or blanking.
+ *
+ * 3. Worker
+ *Does modesetting, blanking and rendering.
+ *It takes a snapshot of the VT text buffer and renders the changes since
+ *last.
+ */
+
+struct drm_vtcon_vc {
+   struct mutex lock;
+
+   u16 *text_buf;
+   size_t buf_len;
+
+   unsigned int rows;
+   unsigned int cols;
+   unsigned int max_rows;
+   unsigned int max_cols;
+   const struct font_desc *font;
+   bool blank;
+   unsigned long cursor_blink_jiffies;
+};
+
+static struct drm_vtcon_vc *drm_vtcon_vc;
+
+struct drm_vtcon {
+   struct drm_client_dev *client;
+   struct drm_client_display *display;
+   struct drm_client_buffer *buffer;
+
+   unsigned int rows;
+   unsigned int cols;
+
+   u16 *text_buf[2];
+   size_t buf_len;
+   unsigned int buf_idx;
+   bool blank;
+};
+
+static struct drm_vtcon *vtcon_instance;
+
+static int drm_vtcon_dev_id;
+module_param_named(dev, drm_vtcon_dev_id, int, 0600);
+MODULE_PARM_DESC(drm_vtcon_dev_id, "DRM device id [default=0]");
+
+#define drm_vtcon_debug(vc, fmt, ...) \
+   pr_debug("%s[%u]: " fmt, __func__, vc->vc_num, ##__VA_ARGS__)
+
+/* CGA color palette: 4-bit RGBI: intense red green blue */
+static const u32 drm_vtcon_paletteX888[16] = {
+   0x, /*  0 black */
+   0x00aa, /*  1 blue */
+   0xaa00, /*  2 green */
+   0x, /*  3 cyan */
+   0x00aa, /*  4 red */
+   0x00aa00aa, /*  5 magenta */
+   0x00aa5500, /*  6 brown */
+   0x00aa, /*  7 light gray */
+   0x0055, /*  8 dark gray */
+   0x00ff, /*  9 bright blue */
+   0x0055ff55, /* 10 bright green */
+   0x0055, /* 11 bright cyan */
+   0x00ff, /* 12 bright red */
+   0x00ff55ff, /* 13 bright magenta */
+   0x0055, /* 14 yellow */
+   0x00ff  /* 15 white */
+};
+
+static void
+drm_vtcon_render_char(struct drm_vtcon *vtcon, unsigned int x, unsigned int y,
+ u16 cc, const struct font_desc *font)
+{
+   struct drm_client_buffer *buffer = vtcon->buffer;
+   unsigned int h, w;
+   const u8 *src;
+   void *dst;
+   u32 *pix;
+   u32 fg_col = drm_vtcon_paletteX888[(cc & 0x0f00) >> 8];
+   u32 bg_col = drm_vtcon_paletteX888[cc >> 12];
+
+   src = font->data + (cc & 0xff) * font->height;
+   dst = vtcon->buffer->vaddr + y * buffer->pitch + x * sizeof(u32);
+
+   for (h = 0; h < font->height; h++) {
+   u8 fontline = *(src + h);
+
+   pix = dst;
+   for 

[RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release()

2018-04-14 Thread Noralf Trønnes
These helpers keep track of fbdev users and drm_driver.last_close will
only restore fbdev when actually in use. Additionally the display is
turned off when the last user is closing. fbcon is a user in this context.

If struct fb_ops is defined in a library, fb_open() takes a ref on the
library (fb_ops.owner) instead of the driver module. Fix that by ensuring
that the driver module is pinned.

The functions are not added to the DRM_FB_HELPER_DEFAULT_OPS() macro,
because some of its users do set fb_open/release themselves.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_fb_helper.c | 54 -
 include/drm/drm_fb_helper.h | 29 ++
 2 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 98e5bc92c9f2..b1124c08b1ed 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -177,7 +177,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct 
drm_fb_helper *fb_helper)
if (!drm_fbdev_emulation || !fb_helper)
return -ENODEV;
 
-   if (READ_ONCE(fb_helper->deferred_setup))
+   if (READ_ONCE(fb_helper->deferred_setup) || 
!READ_ONCE(fb_helper->open_count))
return 0;
 
mutex_lock(_helper->lock);
@@ -368,6 +368,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct 
drm_fb_helper *helper,
INIT_WORK(>dirty_work, drm_fb_helper_dirty_work);
helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
mutex_init(>lock);
+   helper->open_count = 1;
helper->funcs = funcs;
helper->dev = dev;
 }
@@ -620,6 +621,53 @@ int drm_fb_helper_defio_init(struct drm_fb_helper 
*fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_defio_init);
 
+/**
+ * drm_fb_helper_fb_open - implementation for _ops.fb_open
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * Increase fbdev use count.
+ * If _ops is wrapped in a library, pin the driver module.
+ */
+int drm_fb_helper_fb_open(struct fb_info *info, int user)
+{
+   struct drm_fb_helper *fb_helper = info->par;
+   struct drm_device *dev = fb_helper->dev;
+
+   if (info->fbops->owner != dev->driver->fops->owner) {
+   if (!try_module_get(dev->driver->fops->owner))
+   return -ENODEV;
+   }
+
+   fb_helper->open_count++;
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_open);
+
+/**
+ * drm_fb_helper_fb_release - implementation for _ops.fb_release
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * Decrease fbdev use count and turn off if there are no users left.
+ * If _ops is wrapped in a library, unpin the driver module.
+ */
+int drm_fb_helper_fb_release(struct fb_info *info, int user)
+{
+   struct drm_fb_helper *fb_helper = info->par;
+   struct drm_device *dev = fb_helper->dev;
+
+   if (!(--fb_helper->open_count))
+   drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
+
+   if (info->fbops->owner != dev->driver->fops->owner)
+   module_put(dev->driver->fops->owner);
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_release);
+
 /**
  * drm_fb_helper_sys_read - wrapper around fb_sys_read
  * @info: fb_info struct pointer
@@ -1436,6 +1484,10 @@ static int drm_fb_helper_single_fb_probe(struct 
drm_fb_helper *fb_helper,
if (ret < 0)
return ret;
 
+   /* Block restore without users if we do track it */
+   if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
+   fb_helper->open_count = 0;
+
strcpy(fb_helper->fb->comm, "[fbcon]");
return 0;
 }
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5f66f253a97b..330983975d5e 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -184,6 +184,22 @@ struct drm_fb_helper {
 * See also: @deferred_setup
 */
int preferred_bpp;
+
+   /**
+* @open_count:
+*
+* Keeps track of fbdev use to know when to not restore fbdev and to
+* disable the pipeline when the last user is gone.
+*
+* Drivers that use drm_fb_helper_fb_open() as their \.fb_open
+* callback will get an initial value of 0 and get restore based on
+* actual use. Others will get an initial value of 1 which means that
+* fbdev will always be restored. Drivers that call
+* drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
+* initial value to 0 themselves in their _fb_helper_funcs->fb_probe
+* callback.
+*/
+   unsigned int open_count;
 };
 
 /**
@@ -230,6 +246,9 @@ void drm_fb_helper_deferred_io(struct fb_info *info,
   struct list_head *pagelist);
 int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper);
 
+int drm_fb_helper_fb_open(struct fb_info *info, int 

[Bug 199319] Flickering screen on AMDGPU and DC with Linux 4.16-2

2018-04-14 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=199319

Márcio (marcios...@gmail.com) changed:

   What|Removed |Added

 CC||marcios...@gmail.com

--- Comment #15 from Márcio (marcios...@gmail.com) ---
Same problem here, using linux 4.16.2 on Arch Linux and RX 480 DisplayPort, at
2560 x 1080.

No xorg config set. 

Kernel parameter amdgpu.dc=1

The flickering happens eventualy, but when using nightlight gnome feature it
happens more frequently.

-- 
You are receiving this mail because:
You are watching the assignee of the bug.
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[Bug 106048] DIRT: Showdown Rendering broken with NIR

2018-04-14 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=106048

Gregor Münch  changed:

   What|Removed |Added

   Priority|medium  |low
 CC||t_arc...@yahoo.com.au
   Hardware|Other   |x86-64 (AMD64)
 OS|All |Linux (All)

-- 
You are receiving this mail because:
You are the assignee for the bug.___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[Bug 105425] 3D & games produce periodic GPU crashes (Radeon R7 370)

2018-04-14 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=105425

--- Comment #30 from MirceaKitsune  ---
Today's testing reveals an important detail I had missed: There are likely
multiple different crashes taking place... or at most one crash but triggered
by several unrelated occurrences. There is no one option or central point.

In the case of Xonotic: Using shadows (r_shadows 2) was by far the primary
factor... even without that however, a crash may still occur after roughly 3
hours of a match running. The MESA variables I mentioned are likely the source
of the second much rarer crash (seen after 2+ hours).

I don't know how I'm going to get to the bottom of this and find the exact
parameters involved: I can't leave 4 hour matches running every single day, and
even then I'd have to test a combination several days in total. I'll continue
slowly testing, but at this rate expect it to take many months.

-- 
You are receiving this mail because:
You are the assignee for the bug.___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[Bug 106048] DIRT: Showdown Rendering broken with NIR

2018-04-14 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=106048

--- Comment #1 from Gregor Münch  ---
Created attachment 138838
  --> https://bugs.freedesktop.org/attachment.cgi?id=138838=edit
with NIR

-- 
You are receiving this mail because:
You are the assignee for the bug.___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[Bug 106048] DIRT: Showdown Rendering broken with NIR

2018-04-14 Thread bugzilla-daemon
https://bugs.freedesktop.org/show_bug.cgi?id=106048

Bug ID: 106048
   Summary: DIRT: Showdown Rendering broken with NIR
   Product: Mesa
   Version: git
  Hardware: Other
OS: All
Status: NEW
  Severity: normal
  Priority: medium
 Component: Drivers/Gallium/radeonsi
  Assignee: dri-devel@lists.freedesktop.org
  Reporter: gr.mue...@gmail.com
QA Contact: dri-devel@lists.freedesktop.org

Created attachment 138837
  --> https://bugs.freedesktop.org/attachment.cgi?id=138837=edit
without NIR

This can only be reproduced if Advanced Lightning is activated.
The graphics are broken even without NIR, see
https://bugs.freedesktop.org/show_bug.cgi?id=100069
but with NIR its even more bugged (see screenshots).

Extended renderer info (GLX_MESA_query_renderer):
Vendor: X.Org (0x1002)
Device: AMD Radeon HD 7900 Series (TAHITI, DRM 3.25.0,
4.16.0-2-amd-staging-drm-next-git, LLVM 7.0.0) (0x6798)
Version: 18.1.0
Accelerated: yes
Video memory: 3044MB
Unified memory: no
Preferred profile: core (0x1)
Max core profile version: 4.5
Max compat profile version: 3.1
Max GLES1 profile version: 1.1
Max GLES[23] profile version: 3.1
OpenGL vendor string: X.Org
OpenGL renderer string: AMD Radeon HD 7900 Series (TAHITI, DRM 3.25.0,
4.16.0-2-amd-staging-drm-next-git, LLVM 7.0.0)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 18.1.0-devel
(git-6a519a157b)
OpenGL core profile shading language version string: 4.50

-- 
You are receiving this mail because:
You are the assignee for the bug.___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel