All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/17] atomic modeset core<->driver interfaces and helpers
@ 2014-11-02 13:19 Daniel Vetter
  2014-11-02 13:19 ` [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h Daniel Vetter
                   ` (16 more replies)
  0 siblings, 17 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Hi all,

So here's my atomic series, finally debugged. This is just the
core<->driver interface plus a big pile of helpers. Short recap of the main
ideas:

- There are essentially three helper libraries in this patch set:

  * Transitional helpers to use the new plane callbacks for legacy plane
    updates and in the crtc helper's ->mode_set callback. These helpers are
    only temporarily used to convert drivers to atomic, but they allow a
    nice separation between changing the driver backend and switching to
    the atomic commit logic.

  * Legacy helpers to implement all the legacy driver entry points
    (page_flip, set_config, plane vfuncs) on top of the new atomic driver
    interface. These are completely driver agnostic. The reason for having
    the legacy support as helpers is that drivers can switch step-by-step.
    And they could e.g. even keep the legacy page_flip code around for some
    old platforms where converting to full-blown atomic isn't worth it.

  * Atomic helpers which implement the various new ->atomic_* driver
    interfaces in terms of the revised crtc helper and new plane helper
    hooks.

- The revised crtc helper implemenation essentially implements all the
  lessons learned in the i915 modeset rework (when using the atomic helpers
  only):

  * Enable/disable sequence for a given config are always the same and
    callbacks are always called in the same order. This contrast starkly
    with the crtc helpers, where the sequence of operations is heavily
    dependent on the previous config.

    One corollary of this is that if the configuration of a crtc only
    partially changes (e.g. a connector moves in a cloned config) the
    helper code will still disable/enable the full display pipeline. This
    is the only way to ensure that the enable/disable sequence is always
    the same.

  * It won't call disable or enable hooks more than once any more because
    it lost track of state, thanks to the atomic state tracking. And if
    drivers implement the ->reset hook properly (by either resetting the hw
    or reading out the hw state into the atomic structures) this even
    extends to the hardware state. So no more disable-me-harder kind of
    nonsense.

  * The only lacking thing is the hw state readout/cross-check support, but
    if drivers have hw state readout support in their ->reset handlers it's
    simple to extend that to cross-check the hw state.

  * The crtc->mode_set callback is gone and its replacement only sets crtc
    timings an no longer updates the primary plane state. This way we can
    finally implement primary planes properly.

- The new plane helpers should be suitable enough for pretty much
  everything, and a perfect fit for hardware with GO bits. Even if they
  don't fit the atomic helper library is rather flexible and exports all
  the functions for the individual steps to drivers. So drivers can pick
  what matches and implement their own magic for everything.

- A big difference compared to all previous atomic series is that this one
  doesn't implement async commit in a generic way. Imo driver requirements
  for that are too diverse to create anything reasonable sane which would
  actually work on a reasonable amount of different drivers. Also, we've
  never had a helper library for page_flips even, so it's really hard to
  know what might work and what's stupid without a bit of experience.

  I think with the current flexibility for drivers to pick individual
  stages and existing helpers like drm_flip_queue it's rather easy though
  to implement proper async commit.

- There's a few other differences of minor importance to earlier atomic
  series:

  * Common/generic properties are parsed in the callers/core and not in
    drivers, and passed to drivers by directly setting the right members in
    atomic state structures. That greatly simplifies all the transitional
    and legacy helpers an removes a lot of boilerplate code.

  * There's no crazy trylock mode used for the async commit since these
    helpers don't do async commit. A simple ordered flip queue of atomic
    state updates should be sufficient for preventing concurrent hw access
    anyway, as long as synchronous updates stall correctly with e.g.
    flush_work_queue or similar function.

  * These helpers reuse the existing ->mode_fixup hooks in the atomic_check
    callback. Which means that drivers need to adapat and move a lot less code
    into their atomic_check callbacks.

Now this isn't everything needed in the drm core and helpers for full
atomic support. But it's enough to start with converting drivers, and
except for actually testing multiplane and multicrtc updates also enough to
implement full atomic updates. Still missing are:

- Per-plane locking. Since these helpers here encapsulate the locking
  completely this should be fairly easy to implement.

- fbdev support for atomic_check/commit, so that multi-pipe finally works
  sanely.

- Adding and decoding shared/core properties. That just needs to be rebased
  from Rob's latest patch series, with minor adjustments so that the
  decoding happens in the core instead of in drivers.

- Actually adding the atomic ioctl. Again just rebasing Rob's latest patch
  should be all that's needed.

- Finally I couldn't test connector/encoder stealing properly since my test
  vehicle here doesn't allow a connector on different crtcs. So drivers
  which support this might see some surprises in that area.

As just mentioned I've done a fake conversion of an existing driver using
crtc helpers to debug the helper code and validate the smooth transition
approach. And that smooth transition was the really big motivation for
this. It seems to actually work and consists of 3 phases:

Phase 1: Rework driver backend for crtc/plane helpers

The requirement here is that universal plane support is already implement.
When that's done there's two big things to do:

- Split up the existing ->update/disable_plane hooks into check/commit
  hooks and extract the crtc-wide prep/flush parts (like setting/clearing
  GO bits).

- The other big change is to split the crtc->mode_set hook into the plane
  update (done using the plane helpers) and the crtc setup in a new
  ->mode_set_nofb hook.

When phase 1 is complete the driver implements all the new callbacks which
push the software state into hardware, but still using all the legacy entry
points and crtc helpers. The transitional helpers serve as impendance
mismatch here.

Phase 2: Rework state handling

This consists of rolling out the state handling helpers for planes, crtcs
and connectors and reviewing all ->mode_fixup and similar hooks to make
sure they don't depend upon implicit global state which might change. Any
such code must be moved into ->atomic_check functions which just rely on
the free-standing atomic state update structures.

This phase also adds a few small pieces of fixup code to make sure the
atomic state doesn't get out of sync in the legacy driver callbacks.

Phase 3: Roll out atomic support

Now it's just about replacing vfuncs with the ones provided by the helper
and filling out the small missing pieces (like atomic_check logic or async
commit support needed for page_flips). Due to the prep work in phase 1 no
changes to the driver backend functions should be required, and because of
the prep work in phase 2 atomic implementations can be rolled out
step-by-step. So if async commit ins't implemented yet page_flip can be
implemented with the legacy functions without wreaking havoc in the other
operations.

I'm working on a blog post to go a bit more into details of the conversion, too.

The entire pile of patches is available at

http://cgit.freedesktop.org/~danvet/drm/log/?h=colder-fusion

That branch includes the somewhat stubbed-out and hackish conversion of exynos,
but it should be good enough to demonstrate the ideas and concepts.

Since I've wasted so much time getting exynos going here and so many people are
eagerly waiting for this I want to send the pull request to Dave in the next few
days if possible. So please bring on all the review, comments and feedback
quickly.

Cheers, Daniel

Daniel Vetter (17):
  drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h
  drm: Pull drm_crtc.h into the kerneldoc template
  drm: fixup kerneldoc in drm_crtc.h
  drm/modeset_lock: document trylock_only in kerneldoc
  drm: Add atomic driver interface definitions for objects
  drm: Global atomic state handling
  drm: Add atomic/plane helpers
  drm/plane-helper: transitional atomic plane helpers
  drm/crtc-helper: Transitional functions using atomic plane helpers
  drm: Atomic crtc/connector updates using crtc/plane helper interfaces
  drm/atomic-helper: implementatations for legacy interfaces
  drm/atomic: Integrate fence support
  drm/atomic-helpers: document how to implement async commit
  drm/atomic-helper: implement ->page_flip
  drm/atomic-helpers: functions for state duplicate/destroy/reset
  drm: Docbook integration and over sections for all the new helpers
  drm/atomic: Refcounting for plane_state->fb

 Documentation/DocBook/drm.tmpl             |   28 +-
 drivers/gpu/drm/Makefile                   |    4 +-
 drivers/gpu/drm/armada/armada_crtc.c       |    1 +
 drivers/gpu/drm/ast/ast_mode.c             |    1 +
 drivers/gpu/drm/bochs/bochs_kms.c          |    1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       |    1 +
 drivers/gpu/drm/drm_atomic.c               |  615 +++++++++
 drivers/gpu/drm/drm_atomic_helper.c        | 1906 ++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_helper.c          |  132 ++
 drivers/gpu/drm/drm_plane_helper.c         |  198 ++-
 drivers/gpu/drm/gma500/psb_intel_display.c |    1 +
 drivers/gpu/drm/mgag200/mgag200_mode.c     |    1 +
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    |    1 +
 drivers/gpu/drm/nouveau/nv50_display.c     |    1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        |    1 +
 drivers/gpu/drm/qxl/qxl_display.c          |    1 +
 drivers/gpu/drm/radeon/radeon_display.c    |    1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c     |    1 +
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c  |    1 +
 drivers/gpu/drm/sti/sti_drm_crtc.c         |    1 +
 drivers/gpu/drm/tegra/dc.c                 |    1 +
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c       |    1 +
 drivers/gpu/drm/udl/udl_modeset.c          |    1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        |    1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       |    1 +
 drivers/staging/imx-drm/imx-drm-core.c     |    1 +
 include/drm/drm_atomic.h                   |   65 +
 include/drm/drm_atomic_helper.h            |   97 ++
 include/drm/drm_crtc.h                     |  245 +++-
 include/drm/drm_crtc_helper.h              |   13 +
 include/drm/drm_modeset_lock.h             |    1 +
 include/drm/drm_plane_helper.h             |   38 +
 32 files changed, 3326 insertions(+), 36 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 drivers/gpu/drm/drm_atomic_helper.c
 create mode 100644 include/drm/drm_atomic.h
 create mode 100644 include/drm/drm_atomic_helper.h

-- 
2.1.1

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

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

* [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
  2014-11-02 13:19 ` [PATCH 02/17] drm: Pull drm_crtc.h into the kerneldoc template Daniel Vetter
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter

Just a bit of OCD cleanup on headers - this function isn't the core
interface any more but just a helper for drivers who haven't yet
transitioned to universal planes. Put the declaration at the right
spot and sprinkle necessary #includes over all drivers.

Maybe this helps to encourage driver maintainers to do the switch.

Cc: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/armada/armada_crtc.c       | 1 +
 drivers/gpu/drm/ast/ast_mode.c             | 1 +
 drivers/gpu/drm/bochs/bochs_kms.c          | 1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c       | 1 +
 drivers/gpu/drm/gma500/psb_intel_display.c | 1 +
 drivers/gpu/drm/mgag200/mgag200_mode.c     | 1 +
 drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 1 +
 drivers/gpu/drm/nouveau/nv50_display.c     | 1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c        | 1 +
 drivers/gpu/drm/qxl/qxl_display.c          | 1 +
 drivers/gpu/drm/radeon/radeon_display.c    | 1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 1 +
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 1 +
 drivers/gpu/drm/sti/sti_drm_crtc.c         | 1 +
 drivers/gpu/drm/tegra/dc.c                 | 1 +
 drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 1 +
 drivers/gpu/drm/udl/udl_modeset.c          | 1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 1 +
 drivers/staging/imx-drm/imx-drm-core.c     | 1 +
 include/drm/drm_crtc.h                     | 3 ---
 include/drm/drm_plane_helper.h             | 4 ++++
 22 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 9a0cc09e6653..0b164fb1c107 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 19ada0bbe319..df986498d376 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -31,6 +31,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include "ast_drv.h"
 
 #include "ast_tables.h"
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 6b7efcf363d6..5ffd4895d040 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -6,6 +6,7 @@
  */
 
 #include "bochs.h"
+#include <drm/drm_plane_helper.h>
 
 static int defx = 1024;
 static int defy = 768;
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index c7c5a9d91fa0..99d4a74ffeaf 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -16,6 +16,7 @@
  */
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include <video/cirrus.h>
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 87b50ba64ed4..b21a09451d1d 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -21,6 +21,7 @@
 #include <linux/i2c.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_plane_helper.h>
 #include "framebuffer.h"
 #include "psb_drv.h"
 #include "psb_intel_drv.h"
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 83485ab81ce8..9872ba9abf1a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -15,6 +15,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "mgag200_drv.h"
 
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index b90aa5c1f90a..07acb36235cd 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -26,6 +26,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "nouveau_drm.h"
 #include "nouveau_reg.h"
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index fdb3e1adea1e..a1fd99589ce3 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -26,6 +26,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drm_dp_helper.h>
 
 #include <nvif/class.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 2d28dc337cfb..b0566a1ca28f 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -20,6 +20,7 @@
 #include "omap_drv.h"
 
 #include <drm/drm_mode.h>
+#include <drm/drm_plane_helper.h>
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index af9e78546688..b7b728e758b8 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -29,6 +29,7 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 #include "drm_crtc_helper.h"
+#include <drm/drm_plane_helper.h>
 
 static bool qxl_head_enabled(struct qxl_head *head)
 {
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 4eb37976f879..ad24536ee4ce 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -32,6 +32,7 @@
 
 #include <linux/pm_runtime.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drm_edid.h>
 
 #include <linux/gcd.h>
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 148b50589181..088bfd875d29 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -19,6 +19,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_drv.h"
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 0ddce4d046d9..859ccb658601 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -19,6 +19,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include <video/sh_mobile_meram.h>
 
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
index d2ae0c0e13be..36a1ad3c4823 100644
--- a/drivers/gpu/drm/sti/sti_drm_crtc.c
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
@@ -10,6 +10,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "sti_compositor.h"
 #include "sti_drm_drv.h"
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 6553fd238685..7bca8ed47e51 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/reset.h>
+#include <drm/drm_plane_helper.h>
 
 #include "dc.h"
 #include "drm.h"
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d642d4a02134..29ec98baffd1 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -16,6 +16,7 @@
  */
 
 #include "drm_flip_work.h"
+#include <drm/drm_plane_helper.h>
 
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index dc145d320b25..1701f1dfb23f 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include "udl_drv.h"
 
 /*
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 15e185ae4c99..5c289f748ab4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -26,6 +26,7 @@
  **************************************************************************/
 
 #include "vmwgfx_kms.h"
+#include <drm/drm_plane_helper.h>
 
 
 #define vmw_crtc_to_ldu(x) \
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index b295463a60b3..7dc591d04d9a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -26,6 +26,7 @@
  **************************************************************************/
 
 #include "vmwgfx_kms.h"
+#include <drm/drm_plane_helper.h>
 
 
 #define vmw_crtc_to_sou(x) \
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 9cb222e2996f..2f8007241734 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -24,6 +24,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include "imx-drm.h"
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 36a5cbc0cc73..44c57d2a64ec 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -885,9 +885,6 @@ extern int drm_crtc_init_with_planes(struct drm_device *dev,
 				     struct drm_plane *primary,
 				     struct drm_plane *cursor,
 				     const struct drm_crtc_funcs *funcs);
-extern int drm_crtc_init(struct drm_device *dev,
-			 struct drm_crtc *crtc,
-			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
 extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
 
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index 52e6870534b2..0e1dcb163b81 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -42,6 +42,10 @@
  * planes.
  */
 
+extern int drm_crtc_init(struct drm_device *dev,
+			 struct drm_crtc *crtc,
+			 const struct drm_crtc_funcs *funcs);
+
 extern int drm_plane_helper_check_update(struct drm_plane *plane,
 					 struct drm_crtc *crtc,
 					 struct drm_framebuffer *fb,
-- 
2.1.1

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

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

* [PATCH 02/17] drm: Pull drm_crtc.h into the kerneldoc template
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
  2014-11-02 13:19 ` [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-02 19:18   ` [PATCH] " Daniel Vetter
  2014-11-02 13:19 ` [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h Daniel Vetter
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

While writing atomic docs I've noticed that I don't get any errors
for my screw-ups in drm_crtc.h. Fix this immediately.

This just does the bare minimum to get starts, lots of stuff isn't
properly documented yet unfortunately.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |  4 ++++
 include/drm/drm_crtc.h         | 26 +++++++++++++-------------
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index be35bc328b77..89829ae58e97 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -1827,6 +1827,10 @@ void intel_crt_init(struct drm_device *dev)
 !Edrivers/gpu/drm/drm_crtc.c
     </sect2>
     <sect2>
+      <title>KMS Data Structures</title>
+!Iinclude/drm/drm_crtc.h
+    </sect2>
+    <sect2>
       <title>KMS Locking</title>
 !Pdrivers/gpu/drm/drm_modeset_lock.c kms locking
 !Iinclude/drm/drm_modeset_lock.h
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 44c57d2a64ec..21a15850a4d5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -142,7 +142,7 @@ struct drm_framebuffer_funcs {
 	int (*create_handle)(struct drm_framebuffer *fb,
 			     struct drm_file *file_priv,
 			     unsigned int *handle);
-	/**
+	/*
 	 * Optinal callback for the dirty fb ioctl.
 	 *
 	 * Userspace can notify the driver via this callback
@@ -226,7 +226,7 @@ struct drm_plane;
 struct drm_bridge;
 
 /**
- * drm_crtc_funcs - control CRTCs for a given device
+ * struct drm_crtc_funcs - control CRTCs for a given device
  * @save: save CRTC state
  * @restore: restore CRTC state
  * @reset: reset CRTC after state has been invalidated (e.g. resume)
@@ -290,7 +290,7 @@ struct drm_crtc_funcs {
 };
 
 /**
- * drm_crtc - central CRTC control structure
+ * struct drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
  * @mutex: per-CRTC locking
@@ -322,7 +322,7 @@ struct drm_crtc {
 	struct device_node *port;
 	struct list_head head;
 
-	/**
+	/*
 	 * crtc mutex
 	 *
 	 * This provides a read lock for the overall crtc state (mode, dpms
@@ -377,7 +377,7 @@ struct drm_crtc {
 
 
 /**
- * drm_connector_funcs - control connectors on a given device
+ * struct drm_connector_funcs - control connectors on a given device
  * @dpms: set power state (see drm_crtc_funcs above)
  * @save: save connector state
  * @restore: restore connector state
@@ -414,7 +414,7 @@ struct drm_connector_funcs {
 };
 
 /**
- * drm_encoder_funcs - encoder controls
+ * struct drm_encoder_funcs - encoder controls
  * @reset: reset state (e.g. at init or resume time)
  * @destroy: cleanup and free associated data
  *
@@ -428,7 +428,7 @@ struct drm_encoder_funcs {
 #define DRM_CONNECTOR_MAX_ENCODER 3
 
 /**
- * drm_encoder - central DRM encoder structure
+ * struct drm_encoder - central DRM encoder structure
  * @dev: parent DRM device
  * @head: list management
  * @base: base KMS object
@@ -472,7 +472,7 @@ struct drm_encoder {
 #define MAX_ELD_BYTES	128
 
 /**
- * drm_connector - central DRM connector control structure
+ * struct drm_connector - central DRM connector control structure
  * @dev: parent DRM device
  * @kdev: kernel device for sysfs attributes
  * @attr: sysfs attributes
@@ -566,7 +566,7 @@ struct drm_connector {
 };
 
 /**
- * drm_plane_funcs - driver plane control functions
+ * struct drm_plane_funcs - driver plane control functions
  * @update_plane: update the plane configuration
  * @disable_plane: shut down the plane
  * @destroy: clean up plane resources
@@ -594,7 +594,7 @@ enum drm_plane_type {
 };
 
 /**
- * drm_plane - central DRM plane control structure
+ * struct drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
  * @base: base mode object
@@ -632,7 +632,7 @@ struct drm_plane {
 };
 
 /**
- * drm_bridge_funcs - drm_bridge control functions
+ * struct drm_bridge_funcs - drm_bridge control functions
  * @attach: Called during drm_bridge_attach
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
  * @disable: Called right before encoder prepare, disables the bridge
@@ -658,7 +658,7 @@ struct drm_bridge_funcs {
 };
 
 /**
- * drm_bridge - central DRM bridge control structure
+ * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
  * @head: list management
  * @base: base mode object
@@ -679,7 +679,7 @@ struct drm_bridge {
 };
 
 /**
- * drm_mode_set - new values for a CRTC config change
+ * struct drm_mode_set - new values for a CRTC config change
  * @head: list management
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
  2014-11-02 13:19 ` [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h Daniel Vetter
  2014-11-02 13:19 ` [PATCH 02/17] drm: Pull drm_crtc.h into the kerneldoc template Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-02 19:19   ` Daniel Vetter
  2014-11-02 13:19 ` [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc Daniel Vetter
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Vetter, Intel Graphics Development, Thomas Wood,
	Russell King, Daniel Vetter

I've tried to cc all the people who have recently added new stuff
but forgotten to update documentation.

I've also decided not to bother documenting the massive property list
in struct drm_mode_config. If that beast keeps on growing we might want
to extract it into a separate structure which we won't document.

Cc: Thomas Wood <thomas.wood@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 include/drm/drm_crtc.h | 51 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 21a15850a4d5..a68e02be7e37 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -231,6 +231,7 @@ struct drm_bridge;
  * @restore: restore CRTC state
  * @reset: reset CRTC after state has been invalidated (e.g. resume)
  * @cursor_set: setup the cursor
+ * @cursor_set2: setup the cursor with hotspot, superseeds @cursor_set if set
  * @cursor_move: move the cursor
  * @gamma_set: specify color ramp for CRTC
  * @destroy: deinit and free object
@@ -292,11 +293,14 @@ struct drm_crtc_funcs {
 /**
  * struct drm_crtc - central CRTC control structure
  * @dev: parent DRM device
+ * @port: OF node used by drm_of_find_possible_crtcs()
  * @head: list management
  * @mutex: per-CRTC locking
  * @base: base KMS object for ID tracking etc.
  * @primary: primary plane for this CRTC
  * @cursor: cursor plane for this CRTC
+ * @cursor_x: current x position of the cursor, used for universal cursor planes
+ * @cursor_y: current y position of the cursor, used for universal cursor planes
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
@@ -309,10 +313,12 @@ struct drm_crtc_funcs {
  * @gamma_size: size of gamma ramp
  * @gamma_store: gamma ramp values
  * @framedur_ns: precise frame timing
- * @framedur_ns: precise line timing
+ * @linedur_ns: precise line timing
  * @pixeldur_ns: precise pixel timing
  * @helper_private: mid-layer private data
  * @properties: property tracking for this CRTC
+ * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
+ * 	legacy ioctls
  *
  * Each CRTC may have one or more connectors associated with it.  This structure
  * allows the CRTC to be controlled.
@@ -483,6 +489,7 @@ struct drm_encoder {
  * @connector_type_id: index into connector type enum
  * @interlace_allowed: can this connector handle interlaced modes?
  * @doublescan_allowed: can this connector handle doublescan?
+ * @stereo_allowed: can this connector handle stereo modes?
  * @modes: modes available on this connector (from fill_modes() + user)
  * @status: one of the drm_connector_status enums (connected, not, or unknown)
  * @probed_modes: list of modes derived directly from the display
@@ -490,10 +497,13 @@ struct drm_encoder {
  * @funcs: connector control functions
  * @edid_blob_ptr: DRM property containing EDID if present
  * @properties: property tracking for this connector
+ * @path_blob_ptr: DRM blob property data for the DP MST path property
  * @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling
  * @dpms: current dpms state
  * @helper_private: mid-layer private data
+ * @cmdline_mode: mode line parsed from the kernel cmdline for this connector
  * @force: a %DRM_FORCE_<foo> state for forced mode sets
+ * @override_edid: has the EDID been overwritten through debugfs for testing?
  * @encoder_ids: valid encoders for this connector
  * @encoder: encoder driving this connector, if any
  * @eld: EDID-like data, if present
@@ -503,6 +513,8 @@ struct drm_encoder {
  * @video_latency: video latency info from ELD, if found
  * @audio_latency: audio latency info from ELD, if found
  * @null_edid_counter: track sinks that give us all zeros for the EDID
+ * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
+ * @debugfs_entry: debugfs directory for this connector
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -570,6 +582,7 @@ struct drm_connector {
  * @update_plane: update the plane configuration
  * @disable_plane: shut down the plane
  * @destroy: clean up plane resources
+ * @reset: reset plane after state has been invalidated (e.g. resume)
  * @set_property: called when a property is changed
  */
 struct drm_plane_funcs {
@@ -603,6 +616,8 @@ enum drm_plane_type {
  * @format_count: number of formats supported
  * @crtc: currently bound CRTC
  * @fb: currently bound fb
+ * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
+ * 	drm_mode_set_config_internal() to implement correct refcounting.
  * @funcs: helper functions
  * @properties: property tracking for this plane
  * @type: type of plane (overlay, primary, cursor)
@@ -620,8 +635,6 @@ struct drm_plane {
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb;
 
-	/* Temporary tracking of the old fb while a modeset is ongoing. Used
-	 * by drm_mode_set_config_internal to implement correct refcounting. */
 	struct drm_framebuffer *old_fb;
 
 	const struct drm_plane_funcs *funcs;
@@ -680,7 +693,6 @@ struct drm_bridge {
 
 /**
  * struct drm_mode_set - new values for a CRTC config change
- * @head: list management
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
  * @mode: mode timings to use
@@ -722,10 +734,11 @@ struct drm_mode_config_funcs {
 };
 
 /**
- * drm_mode_group - group of mode setting resources for potential sub-grouping
+ * struct drm_mode_group - group of mode setting resources for potential sub-grouping
  * @num_crtcs: CRTC count
  * @num_encoders: encoder count
  * @num_connectors: connector count
+ * @num_bridges: bridge count
  * @id_list: list of KMS object IDs in this group
  *
  * Currently this simply tracks the global mode setting state.  But in the
@@ -745,10 +758,14 @@ struct drm_mode_group {
 };
 
 /**
- * drm_mode_config - Mode configuration control structure
+ * struct drm_mode_config - Mode configuration control structure
  * @mutex: mutex protecting KMS related lists and structures
+ * @connection_mutex: ww mutex protecting connector state and routing
+ * @acquire_ctx: global implicit acquire context used by atomic drivers for
+ * 	legacy ioctls
  * @idr_mutex: mutex for KMS ID allocation and management
  * @crtc_idr: main KMS ID tracking object
+ * @fb_lock: mutex to protect fb state and lists
  * @num_fb: number of fbs available
  * @fb_list: list of framebuffers available
  * @num_connector: number of connectors on this device
@@ -757,17 +774,28 @@ struct drm_mode_group {
  * @bridge_list: list of bridge objects
  * @num_encoder: number of encoders on this device
  * @encoder_list: list of encoder objects
+ * @num_overlay_plane: number of overlay planes on this device
+ * @num_total_plane: number of universal (i.e. with primary/curso) planes on this device
+ * @plane_list: list of plane objects
  * @num_crtc: number of CRTCs on this device
  * @crtc_list: list of CRTC objects
+ * @property_list: list of property objects
  * @min_width: minimum pixel width on this device
  * @min_height: minimum pixel height on this device
  * @max_width: maximum pixel width on this device
  * @max_height: maximum pixel height on this device
  * @funcs: core driver provided mode setting functions
  * @fb_base: base address of the framebuffer
- * @poll_enabled: track polling status for this device
+ * @poll_enabled: track polling support for this device
+ * @poll_running: track polling status for this device
  * @output_poll_work: delayed work for polling in process context
+ * @property_blob_list: list of all the blob property objects
  * @*_property: core property tracking
+ * @preferred_depth: preferred RBG pixel depth, used by fb helpers
+ * @prefer_shadow: hint to userspace to prefer shadow-fb rendering
+ * @async_page_flip: does this device support async flips on the primary plane?
+ * @cursor_width: hint to userspace for max cursor width
+ * @cursor_height: hint to userspace for max cursor height
  *
  * Core mode resource tracking structure.  All CRTC, encoders, and connectors
  * enumerated by the driver are added here, as are global properties.  Some
@@ -781,14 +809,7 @@ struct drm_mode_config {
 	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
 	/* this is limited to one for now */
 
-
-	/**
-	 * fb_lock - mutex to protect fb state
-	 *
-	 * Besides the global fb list his also protects the fbs list in the
-	 * file_priv
-	 */
-	struct mutex fb_lock;
+	struct mutex fb_lock; /* proctects global and per-file fb lists */
 	int num_fb;
 	struct list_head fb_list;
 
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (2 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
  2014-11-05 16:18   ` Thierry Reding
  2014-11-02 13:19 ` [PATCH 05/17] drm: Add atomic driver interface definitions for objects Daniel Vetter
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter

I've forgotten to do this in:

commit cb597bb3a2fbfc871cc1c703fb330d247bd21394
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Sun Jul 27 19:09:33 2014 +0200

    drm: trylock modest locking for fbdev panics

Oops, fix this asap.

In my defense kerneldoc is really awful and there's no way it can pick
up structured comments per struct member. Which means we need both
since people won't scroll up even a few lines.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 include/drm/drm_modeset_lock.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
index 75a5c45e21c7..28931a23d96c 100644
--- a/include/drm/drm_modeset_lock.h
+++ b/include/drm/drm_modeset_lock.h
@@ -33,6 +33,7 @@ struct drm_modeset_lock;
  * @ww_ctx: base acquire ctx
  * @contended: used internally for -EDEADLK handling
  * @locked: list of held locks
+ * @trylock_only: trylock mode used in atomic contexts/panic notifiers
  *
  * Each thread competing for a set of locks must use one acquire
  * ctx.  And if any lock fxn returns -EDEADLK, it must backoff and
-- 
2.1.1

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

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

* [PATCH 05/17] drm: Add atomic driver interface definitions for objects
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (3 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
  2014-11-05 16:26   ` Thierry Reding
  2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
                   ` (11 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Heavily based upon Rob Clark's atomic series.
- Dropped the connctor state from the crtc state, instead opting for a
  full-blown connector state. The only thing it has is the desired
  crtc, but drivers which have connector properties have now a
  data-structure to subclass.

- Rename create_state to duplicate_state. Especially for legacy ioctls
  we want updates on top of existing state, so we need a way to get at
  the current state. We need to be careful to clear the backpointers
  to the global state correctly though.

- Drop property values. Drivers with properties simply need to
  subclass the datastructures and track the decoded values in there. I
  also think that common properties (like rotation) should be decoded
  and stored in the core structures.

- Create a new set of ->atomic_set_prop functions, for smoother
  transitions from legacy to atomic operations.

- Pass the ->atomic_set_prop ioctl the right structure to avoid
  chasing pointers in drivers.

- Drop temporary boolean state for now until we resurrect them with
  the helper functions.

- Drop invert_dimensions. For now we don't need any checking since
  that's done by the higher-level legacy ioctls. But even then we
  should also add rotation/flip tracking to the core drm_crtc_state,
  not just whether the dimensions are inverted.

- Track crtc state with an enable/disable. That's equivalent to
  mode_valid, but a bit clearer that it means the entire crtc.

The global interface will follow in subsequent patches.

v2: We need to allow drivers to somehow set up the initial state and
clear it on resume. So add a plane->reset callback for that. Helpers
will be provided with default behaviour for all these.

v3: Split out the plane->reset into a separate patch.

v4: Improve kerneldoc in drm_crtc.h

v5: Remove unused inline functions for handling state objects, those
callbacks are now mandatory for full atomic support.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 include/drm/drm_crtc.h | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index a68e02be7e37..9847009ad451 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -224,6 +224,25 @@ struct drm_encoder;
 struct drm_pending_vblank_event;
 struct drm_plane;
 struct drm_bridge;
+struct drm_atomic_state;
+
+/**
+ * struct drm_crtc_state - mutable crtc state
+ * @enable: whether the CRTC should be enabled, gates all other state
+ * @mode: current mode timings
+ * @event: optional pointer to a DRM event to signal upon completion of the
+ * 	state update
+ * @state: backpointer to global drm_atomic_state
+ */
+struct drm_crtc_state {
+	bool enable        : 1;
+
+	struct drm_display_mode mode;
+
+	struct drm_pending_vblank_event *event;
+
+	struct drm_atomic_state *state;
+};
 
 /**
  * struct drm_crtc_funcs - control CRTCs for a given device
@@ -238,6 +257,9 @@ struct drm_bridge;
  * @set_property: called when a property is changed
  * @set_config: apply a new CRTC configuration
  * @page_flip: initiate a page flip
+ * @atomic_duplicate_state: duplicate the atomic state for this CRTC
+ * @atomic_destroy_state: destroy an atomic state for this CRTC
+ * @atomic_set_property: set a property on an atomic state for this CRTC
  *
  * The drm_crtc_funcs structure is the central CRTC management structure
  * in the DRM.  Each CRTC controls one or more connectors (note that the name
@@ -288,6 +310,15 @@ struct drm_crtc_funcs {
 
 	int (*set_property)(struct drm_crtc *crtc,
 			    struct drm_property *property, uint64_t val);
+
+	/* atomic update handling */
+	struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
+	void (*atomic_destroy_state)(struct drm_crtc *crtc,
+				     struct drm_crtc_state *cstate);
+	int (*atomic_set_property)(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state,
+				   struct drm_property *property,
+				   uint64_t val);
 };
 
 /**
@@ -317,6 +348,7 @@ struct drm_crtc_funcs {
  * @pixeldur_ns: precise pixel timing
  * @helper_private: mid-layer private data
  * @properties: property tracking for this CRTC
+ * @state: current atomic state for this CRTC
  * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
  * 	legacy ioctls
  *
@@ -374,6 +406,8 @@ struct drm_crtc {
 
 	struct drm_object_properties properties;
 
+	struct drm_crtc_state *state;
+
 	/*
 	 * For legacy crtc ioctls so that atomic drivers can get at the locking
 	 * acquire context.
@@ -381,6 +415,16 @@ struct drm_crtc {
 	struct drm_modeset_acquire_ctx *acquire_ctx;
 };
 
+/**
+ * struct drm_connector_state - mutable connector state
+ * @crtc: crtc to connect connector to, NULL if disabled
+ * @state: backpointer to global drm_atomic_state
+ */
+struct drm_connector_state {
+	struct drm_crtc *crtc;
+
+	struct drm_atomic_state *state;
+};
 
 /**
  * struct drm_connector_funcs - control connectors on a given device
@@ -393,6 +437,10 @@ struct drm_crtc {
  * @set_property: property for this connector may need an update
  * @destroy: make object go away
  * @force: notify the driver that the connector is forced on
+ * @atomic_duplicate_state: duplicate the atomic state for this connector
+ * @atomic_destroy_state: destroy an atomic state for this connector
+ * @atomic_set_property: set a property on an atomic state for this connector
+ *
  *
  * Each CRTC may have one or more connectors attached to it.  The functions
  * below allow the core DRM code to control connectors, enumerate available modes,
@@ -417,6 +465,15 @@ struct drm_connector_funcs {
 			     uint64_t val);
 	void (*destroy)(struct drm_connector *connector);
 	void (*force)(struct drm_connector *connector);
+
+	/* atomic update handling */
+	struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
+	void (*atomic_destroy_state)(struct drm_connector *connector,
+				     struct drm_connector_state *cstate);
+	int (*atomic_set_property)(struct drm_connector *connector,
+				   struct drm_connector_state *state,
+				   struct drm_property *property,
+				   uint64_t val);
 };
 
 /**
@@ -515,6 +572,7 @@ struct drm_encoder {
  * @null_edid_counter: track sinks that give us all zeros for the EDID
  * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
  * @debugfs_entry: debugfs directory for this connector
+ * @state: current atomic state for this connector
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -575,8 +633,42 @@ struct drm_connector {
 	unsigned bad_edid_counter;
 
 	struct dentry *debugfs_entry;
+
+	struct drm_connector_state *state;
+};
+
+/**
+ * struct drm_plane_state - mutable plane state
+ * @crtc: currently bound CRTC, NULL if disabled
+ * @fb: currently bound fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ *	plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ *	plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @state: backpointer to global drm_atomic_state
+ */
+struct drm_plane_state {
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+
+	/* Signed dest location allows it to be partially off screen */
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
+
+	/* Source values are 16.16 fixed point */
+	uint32_t src_x, src_y;
+	uint32_t src_h, src_w;
+
+	struct drm_atomic_state *state;
 };
 
+
 /**
  * struct drm_plane_funcs - driver plane control functions
  * @update_plane: update the plane configuration
@@ -584,6 +676,9 @@ struct drm_connector {
  * @destroy: clean up plane resources
  * @reset: reset plane after state has been invalidated (e.g. resume)
  * @set_property: called when a property is changed
+ * @atomic_duplicate_state: duplicate the atomic state for this plane
+ * @atomic_destroy_state: destroy an atomic state for this plane
+ * @atomic_set_property: set a property on an atomic state for this plane
  */
 struct drm_plane_funcs {
 	int (*update_plane)(struct drm_plane *plane,
@@ -598,6 +693,15 @@ struct drm_plane_funcs {
 
 	int (*set_property)(struct drm_plane *plane,
 			    struct drm_property *property, uint64_t val);
+
+	/* atomic update handling */
+	struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
+	void (*atomic_destroy_state)(struct drm_plane *plane,
+				     struct drm_plane_state *cstate);
+	int (*atomic_set_property)(struct drm_plane *plane,
+				   struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t val);
 };
 
 enum drm_plane_type {
@@ -621,6 +725,7 @@ enum drm_plane_type {
  * @funcs: helper functions
  * @properties: property tracking for this plane
  * @type: type of plane (overlay, primary, cursor)
+ * @state: current atomic state for this plane
  */
 struct drm_plane {
 	struct drm_device *dev;
@@ -642,6 +747,8 @@ struct drm_plane {
 	struct drm_object_properties properties;
 
 	enum drm_plane_type type;
+
+	struct drm_plane_state *state;
 };
 
 /**
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 06/17] drm: Global atomic state handling
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (4 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 05/17] drm: Add atomic driver interface definitions for objects Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-03 23:41   ` Matt Roper
                     ` (2 more replies)
  2014-11-02 13:19 ` [PATCH 07/17] drm: Add atomic/plane helpers Daniel Vetter
                   ` (10 subsequent siblings)
  16 siblings, 3 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

Cc: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/Makefile     |   2 +-
 drivers/gpu/drm/drm_atomic.c | 588 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h     |  63 +++++
 include/drm/drm_crtc.h       |  35 +++
 4 files changed, 687 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index a3149e20a249..2e89cd50c14f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..c6db8a48cad6
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This functions returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This functions returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This functions returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	conn_state->crtc = crtc;
+
+	DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+		      conn_state, crtc->base.id);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This functions walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on etuccess, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async onfiguration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..753812034e71
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+				  struct drm_crtc *crtc);
+int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				      struct drm_crtc *crtc);
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int drm_atomic_check_only(struct drm_atomic_state *state);
+int drm_atomic_commit(struct drm_atomic_state *state);
+int drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 9847009ad451..c3ce5b36da5f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -799,6 +799,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+       struct drm_device *dev;
+       uint32_t flags;
+       struct drm_plane **planes;
+       struct drm_plane_state **plane_states;
+       struct drm_crtc **crtcs;
+       struct drm_crtc_state **crtc_states;
+       struct drm_connector **connectors;
+       struct drm_connector_state **connector_states;
+
+       struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -829,6 +855,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -838,6 +867,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 07/17] drm: Add atomic/plane helpers
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (5 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 22:30   ` Sean Paul
  2014-11-02 13:19 ` [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers Daniel Vetter
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

This is the first cut of atomic helper code. As-is it's only useful to
implement a pure atomic interface for plane updates.

Later patches will integrate this with the crtc helpers so that full
atomic updates are possible. We also need a pile of helpers to aid
drivers in transitioning from the legacy world to the shiny new atomic
age. Finally we need helpers to implement legacy ioctls on top of the
atomic interface.

The design of the overall helpers<->driver interaction is fairly
simple, but has an unfortunate large interface:

- We have ->atomic_check callbacks for crtcs and planes. The idea is
  that connectors don't need any checking, and if they do they can
  adjust the relevant crtc driver-private state. So no connector hooks
  should be needed. Also the crtc helpers integration will do the
  ->best_encoder checks, so no need for that.

- Framebuffer pinning needs to be done before we can commit to the hw
  state. This is especially important for async updates where we must
  pin all buffers before returning to userspace, so that really only
  hw failures can happen in the asynchronous worker.

  Hence we add ->prepare_fb and ->cleanup_fb hooks for this resources
  management.

- The actual atomic plane commit can't fail (except hw woes), so has
  void return type. It has three stages:
  1. Prepare all affected crtcs with crtc->atomic_begin. Drivers can
     use this to unset the GO bit or similar latches to prevent plane
     updates.
  2. Update plane state by looping over all changed planes and calling
     plane->atomic_update. Presuming the hardware is sane and has GO
     bits drivers can simply bash the state into the hardware in this
     function. Other drivers might use this to precompute hw state for
     the final step.
  3. Finally latch the update for the next vblank with
     crtc->atomic_flush. Note that this function doesn't need to wait
     for the vblank to happen even for the synchronous case.

v2: Clear drm_<obj>_state->state to NULL when swapping in state.

v3: Add TODO that we don't short-circuit plane updates for now. Likely
no one will care.

v4: Squash in a bit of polish that somehow landed in the wrong (later)
patche.

v5: Integrate atomic functions into the drm docbook and fixup the
kerneldoc.

v6: Fixup fixup patch squashing fumble.

v7: Don't touch the legacy plane state plane->fb and plane->crtc. This
is only used by the legacy ioctl code in the drm core, and that code
already takes care of updating the pointers in all relevant cases.
This is in stark contrast to connector->encoder->crtc links on the
modeset side, which we still need to set since the core doesn't touch
them.

Also some more kerneldoc polish.

v8: Drop outdated comment.

v9: Handle the state->state pointer correctly: Only clearing the
->state pointer when assigning the state to the kms object isn't good
enough. We also need to re-link the swapped out state into the
drm_atomic_state structure.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl      |   4 +
 drivers/gpu/drm/Makefile            |   2 +-
 drivers/gpu/drm/drm_atomic_helper.c | 355 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  44 +++++
 include/drm/drm_crtc.h              |   6 +
 include/drm/drm_crtc_helper.h       |   6 +
 include/drm/drm_plane_helper.h      |  22 +++
 7 files changed, 438 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic_helper.c
 create mode 100644 include/drm/drm_atomic_helper.h

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 89829ae58e97..ea0ef43b19e1 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
 !Edrivers/gpu/drm/drm_modes.c
     </sect2>
     <sect2>
+      <title>Atomic Mode Setting Function Reference</title>
+!Edrivers/gpu/drm/drm_atomic.c
+    </sect2>
+    <sect2>
       <title>Frame Buffer Creation</title>
       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
 				     struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 2e89cd50c14f..96338e349a24 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -24,7 +24,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o
 drm-$(CONFIG_OF) += drm_of.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_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
new file mode 100644
index 000000000000..55a8eb2678b0
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+static void
+drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
+				struct drm_plane_state *plane_state,
+				struct drm_plane *plane)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (plane->state->crtc) {
+		crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
+
+		if (WARN_ON(!crtc_state))
+			return;
+
+		crtc_state->planes_changed = true;
+	}
+
+	if (plane_state->crtc) {
+		crtc_state =
+			state->crtc_states[drm_crtc_index(plane_state->crtc)];
+
+		if (WARN_ON(!crtc_state))
+			return;
+
+		crtc_state->planes_changed = true;
+	}
+}
+
+/**
+ * drm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is physically possible.
+ * Only crtcs and planes have check callbacks, so for any additional (global)
+ * checking that a driver needs it can simply wrap that around this function.
+ * Drivers without such needs can directly use this as their ->atomic_check()
+ * callback.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_check(struct drm_device *dev,
+			    struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane_helper_funcs *funcs;
+		struct drm_plane *plane = state->planes[i];
+		struct drm_plane_state *plane_state = state->plane_states[i];
+
+		if (!plane)
+			continue;
+
+		funcs = plane->helper_private;
+
+		drm_atomic_helper_plane_changed(state, plane_state, plane);
+
+		if (!funcs || !funcs->atomic_check)
+			continue;
+
+		ret = funcs->atomic_check(plane, plane_state);
+		if (ret) {
+			DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n",
+				      plane->base.id);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		if (!funcs || !funcs->atomic_check)
+			continue;
+
+		ret = funcs->atomic_check(crtc, state->crtc_states[i]);
+		if (ret) {
+			DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n",
+				      crtc->base.id);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_check);
+
+/**
+ * drm_atomic_helper_prepare_planes - prepare plane resources after commit
+ * @dev: DRM device
+ * @state: atomic state object with old state structures
+ *
+ * This function prepares plane state, specifically framebuffers, for the new
+ * configuration. If any failure is encountered this function will call
+ * ->cleanup_fb on any already successfully prepared framebuffer.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_helper_prepare_planes(struct drm_device *dev,
+				     struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int ret, i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane_helper_funcs *funcs;
+		struct drm_plane *plane = state->planes[i];
+		struct drm_framebuffer *fb;
+
+		if (!plane)
+			continue;
+
+		funcs = plane->helper_private;
+
+		fb = state->plane_states[i]->fb;
+
+		if (fb && funcs->prepare_fb) {
+			ret = funcs->prepare_fb(plane, fb);
+			if (ret)
+				goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	for (i--; i >= 0; i--) {
+		struct drm_plane_helper_funcs *funcs;
+		struct drm_plane *plane = state->planes[i];
+		struct drm_framebuffer *fb;
+
+		if (!plane)
+			continue;
+
+		funcs = plane->helper_private;
+
+		fb = state->plane_states[i]->fb;
+
+		if (fb && funcs->cleanup_fb)
+			funcs->cleanup_fb(plane, fb);
+
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
+
+/**
+ * drm_atomic_helper_commit_planes - commit plane state
+ * @dev: DRM device
+ * @state: atomic state
+ *
+ * This function commits the new plane state using the plane and atomic helper
+ * functions for planes and crtcs. It assumes that the atomic state has already
+ * been pushed into the relevant object state pointers, since this step can no
+ * longer fail.
+ *
+ * It still requires the global state object @state to know which planes and
+ * crtcs need to be updated though.
+ */
+void drm_atomic_helper_commit_planes(struct drm_device *dev,
+				     struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
+	int i;
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		if (!funcs || !funcs->atomic_begin)
+			continue;
+
+		funcs->atomic_begin(crtc);
+	}
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane_helper_funcs *funcs;
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		funcs = plane->helper_private;
+
+		if (!funcs || !funcs->atomic_update)
+			continue;
+
+		funcs->atomic_update(plane);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		if (!funcs || !funcs->atomic_flush)
+			continue;
+
+		funcs->atomic_flush(crtc);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
+
+/**
+ * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
+ * @dev: DRM device
+ * @old_state: atomic state object with old state structures
+ *
+ * This function cleans up plane state, specifically framebuffers, from the old
+ * configuration. Hence the old configuration must be perserved in @old_state to
+ * be able to call this function.
+ *
+ * This function must also be called on the new state when the atomic update
+ * fails at any point after calling drm_atomic_helper_prepare_planes().
+ */
+void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
+				      struct drm_atomic_state *old_state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane_helper_funcs *funcs;
+		struct drm_plane *plane = old_state->planes[i];
+		struct drm_framebuffer *old_fb;
+
+		if (!plane)
+			continue;
+
+		funcs = plane->helper_private;
+
+		old_fb = old_state->plane_states[i]->fb;
+
+		if (old_fb && funcs->cleanup_fb)
+			funcs->cleanup_fb(plane, old_fb);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
+
+/**
+ * drm_atomic_helper_swap_state - store atomic state into current sw state
+ * @dev: DRM device
+ * @state: atomic state
+ *
+ * This function stores the atomic state into the current state pointers in all
+ * driver objects. It should be called after all failing steps have been done
+ * and succeeded, but before the actual hardware state is committed.
+ *
+ * For cleanup and error recovery the current state for all changed objects will
+ * be swaped into @state.
+ *
+ * With that sequence it fits perfectly into the plane prepare/cleanup sequence:
+ *
+ * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state.
+ *
+ * 2. Do any other steps that might fail.
+ *
+ * 3. Put the staged state into the current state pointers with this function.
+ *
+ * 4. Actually commit the hardware state.
+ *
+ * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3
+ * contains the old state. Also do any other cleanup required with that state.
+ */
+void drm_atomic_helper_swap_state(struct drm_device *dev,
+				  struct drm_atomic_state *state)
+{
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->state->state = state;
+		swap(state->connector_states[i], connector->state);
+		connector->state->state = NULL;
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->state->state = state;
+		swap(state->crtc_states[i], crtc->state);
+		crtc->state->state = NULL;
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->state->state = state;
+		swap(state->plane_states[i], plane->state);
+		plane->state->state = NULL;
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_swap_state);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
new file mode 100644
index 000000000000..79938c62e7ad
--- /dev/null
+++ b/include/drm/drm_atomic_helper.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_HELPER_H_
+#define DRM_ATOMIC_HELPER_H_
+
+int drm_atomic_helper_check(struct drm_device *dev,
+			    struct drm_atomic_state *state);
+
+int drm_atomic_helper_prepare_planes(struct drm_device *dev,
+				     struct drm_atomic_state *state);
+void drm_atomic_helper_commit_planes(struct drm_device *dev,
+				     struct drm_atomic_state *state);
+void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
+				      struct drm_atomic_state *old_state);
+
+void drm_atomic_helper_swap_state(struct drm_device *dev,
+				  struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c3ce5b36da5f..d0068b7af678 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -229,6 +229,7 @@ struct drm_atomic_state;
 /**
  * struct drm_crtc_state - mutable crtc state
  * @enable: whether the CRTC should be enabled, gates all other state
+ * @planes_changed: for use by helpers and drivers when computing state updates
  * @mode: current mode timings
  * @event: optional pointer to a DRM event to signal upon completion of the
  * 	state update
@@ -237,6 +238,9 @@ struct drm_atomic_state;
 struct drm_crtc_state {
 	bool enable        : 1;
 
+	/* computed state bits used by helpers and drivers */
+	bool planes_changed : 1;
+
 	struct drm_display_mode mode;
 
 	struct drm_pending_vblank_event *event;
@@ -748,6 +752,8 @@ struct drm_plane {
 
 	enum drm_plane_type type;
 
+	void *helper_private;
+
 	struct drm_plane_state *state;
 };
 
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index a3d75fefd010..adec48b27aa5 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -81,6 +81,12 @@ struct drm_crtc_helper_funcs {
 
 	/* disable crtc when not in use - more explicit than dpms off */
 	void (*disable)(struct drm_crtc *crtc);
+
+	/* atomic helpers */
+	int (*atomic_check)(struct drm_crtc *crtc,
+			    struct drm_crtc_state *state);
+	void (*atomic_begin)(struct drm_crtc *crtc);
+	void (*atomic_flush)(struct drm_crtc *crtc);
 };
 
 /**
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index 0e1dcb163b81..c2146a7d91fb 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -46,6 +46,28 @@ extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 const struct drm_crtc_funcs *funcs);
 
+/**
+ * drm_plane_helper_funcs - helper operations for CRTCs
+ *
+ * The helper operations are called by the mid-layer CRTC helper.
+ */
+struct drm_plane_helper_funcs {
+	int (*prepare_fb)(struct drm_plane *plane,
+			  struct drm_framebuffer *fb);
+	void (*cleanup_fb)(struct drm_plane *plane,
+			   struct drm_framebuffer *fb);
+
+	int (*atomic_check)(struct drm_plane *plane,
+			    struct drm_plane_state *state);
+	void (*atomic_update)(struct drm_plane *plane);
+};
+
+static inline void drm_plane_helper_add(struct drm_plane *plane,
+					const struct drm_plane_helper_funcs *funcs)
+{
+	plane->helper_private = (void *)funcs;
+}
+
 extern int drm_plane_helper_check_update(struct drm_plane *plane,
 					 struct drm_crtc *crtc,
 					 struct drm_framebuffer *fb,
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (6 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 07/17] drm: Add atomic/plane helpers Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-05 16:45   ` Sean Paul
  2014-11-05 16:59   ` [PATCH] " Daniel Vetter
  2014-11-02 13:19 ` [PATCH 09/17] drm/crtc-helper: Transitional functions using " Daniel Vetter
                   ` (8 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Converting a driver to the atomic interface can be a daunting
undertaking. One of the prerequisites is to have full universal planes
support.

To make that transition a bit easier this pathc provides plane helpers
which use the new atomic helper callbacks just only for the plane
changes. This way the plane update functionality can be tested without
being forced to convert everything at once.

Of course a real atomic update capable driver will implement the
all plane properties through the atomic interface, so these helpers
are mostly transitional. But they can be used to enable proper
universal plane support, especially once the crtc helpers have also
been adapted.

v2: Use ->atomic_duplicate_state if available.

v3: Don't forget to call ->atomic_destroy_state if available.

v4: Fixup kerneldoc, reported by Paulo.

v5: Extract a common plane_commit helper and fix some bugs in the
plane_state setup of the plane_disable implementation.

v6: Fix issues with the cleanup of the old fb. Since transitional
helpers can be mixed we need to assume that the old fb has been set up
by a legacy path (e.g. set_config or page_flip when the primary plane
is converted to use these functions already). Hence pass an additional
old_fb parameter to plane_commit to do that cleanup work correctly.

v7:
- Fix spurious WARNING (crtc helpers really love to disable stuff
  harder) and fix array index bonghits.
- Correctly handle the lack of plane->state object, necessary for
  transitional use.
- Don't indicate failure if drm_vblank_get doesn't work - that's
  expected when the pipe is in dpms off mode.

Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_plane_helper.c | 172 ++++++++++++++++++++++++++++++++++++-
 include/drm/drm_plane_helper.h     |   8 ++
 2 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 827ec1a3040b..45aa8c98e3fb 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -27,7 +27,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -369,3 +369,173 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
 }
 EXPORT_SYMBOL(drm_crtc_init);
+
+static int
+plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
+	     struct drm_framebuffer *old_fb)
+{
+	struct drm_plane_helper_funcs *plane_funcs;
+	struct drm_crtc *crtc[2];
+	struct drm_crtc_helper_funcs *crtc_funcs[2];
+	int i, ret = 0;
+
+	plane_funcs = plane->helper_private;
+
+	/* Since this is a transitional helper we can't assume that plane->state
+	 * is always valid. Hence we need to use plane->crtc instead of
+	 * plane->state->crtc as the old crtc. */
+	crtc[0] = plane->crtc;
+	crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
+
+	for (i = 0; i < 2; i++)
+		crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
+
+	if (plane_funcs->atomic_check) {
+		ret = plane_funcs->atomic_check(plane, plane_state);
+		if (ret)
+			goto fail;
+	}
+
+	if (plane_funcs->prepare_fb && plane_state->fb) {
+		ret = plane_funcs->prepare_fb(plane, plane_state->fb);
+		if (ret)
+			goto fail;
+	}
+
+	/* Point of no return, commit sw state. */
+	swap(plane->state, plane_state);
+
+	for (i = 0; i < 2; i++) {
+		if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
+			crtc_funcs[i]->atomic_begin(crtc[i]);
+	}
+
+	plane_funcs->atomic_update(plane);
+
+	for (i = 0; i < 2; i++) {
+		if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
+			crtc_funcs[i]->atomic_flush(crtc[i]);
+	}
+
+	for (i = 0; i < 2; i++) {
+		if (!crtc[i])
+			continue;
+
+		/* There's no other way to figure out whether the crtc is running. */
+		ret = drm_crtc_vblank_get(crtc[i]);
+		if (ret == 0) {
+			drm_crtc_wait_one_vblank(crtc[i]);
+			drm_crtc_vblank_put(crtc[i]);
+		}
+
+		ret = 0;
+	}
+
+	if (plane_funcs->cleanup_fb && old_fb)
+		plane_funcs->cleanup_fb(plane, old_fb);
+fail:
+	if (plane_state) {
+		if (plane->funcs->atomic_destroy_state)
+			plane->funcs->atomic_destroy_state(plane, plane_state);
+		else
+			kfree(plane_state);
+	}
+
+	return ret;
+}
+
+/**
+ * drm_plane_helper_update() - Helper for primary plane update
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb,
+			    int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h)
+{
+	struct drm_plane_state *plane_state;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = crtc;
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	return plane_commit(plane, plane_state, plane->fb);
+}
+EXPORT_SYMBOL(drm_plane_helper_update);
+
+/**
+ * drm_plane_helper_disable() - Helper for primary plane disable
+ * @plane: plane to disable
+ *
+ * Provides a default plane disable handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_disable(struct drm_plane *plane)
+{
+	struct drm_plane_state *plane_state;
+
+	/* crtc helpers love to call disable functions for already disabled hw
+	 * functions. So cope with that. */
+	if (!plane->crtc)
+		return 0;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = NULL;
+	plane_state->fb = NULL;
+
+	return plane_commit(plane, plane_state, plane->fb);
+}
+EXPORT_SYMBOL(drm_plane_helper_disable);
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index c2146a7d91fb..8a0709704af0 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -94,4 +94,12 @@ extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
 							 int num_formats);
 
 
+int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb,
+			    int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h);
+int drm_plane_helper_disable(struct drm_plane *plane);
+
 #endif
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 09/17] drm/crtc-helper: Transitional functions using atomic plane helpers
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (7 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-05 17:42   ` Sean Paul
  2014-11-02 13:19 ` [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces Daniel Vetter
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

These two functions allow drivers to reuse their atomic plane helpers
functions for the primary plane to implement the interfaces required
by the crtc helpers for the legacy ->set_config callback.

This is purely transitional and won't be used once the driver is fully
converted. But it allows partial conversions to the atomic plane
helpers which are functional.

v2:
- Use ->atomic_duplicate_state if available.
- Don't forget to run crtc_funcs->atomic_check.

v3: Shift source coordinates correctly for 16.16 fixed point.

v4: Don't forget to call ->atomic_destroy_state if available.

v5: Fixup kerneldoc.

v6: Reuse the plane_commit function from the transitional plane
helpers to avoid too much duplication.

v7:
- Remove some stale comment.
- Correctly handle the lack of plane->state object, necessary for
  transitional use.

v8: Fixup an embarrassing h/vdisplay mixup.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc_helper.c  | 110 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_plane_helper.c |  10 ++--
 include/drm/drm_crtc.h             |   4 ++
 include/drm/drm_crtc_helper.h      |   7 +++
 include/drm/drm_plane_helper.h     |   4 ++
 5 files changed, 130 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 6c65a0a28fbd..95ecbb131053 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -38,6 +38,7 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drm_edid.h>
 
 MODULE_AUTHOR("David Airlie, Jesse Barnes");
@@ -888,3 +889,112 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
 	drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
+
+/**
+ * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
+ * @crtc: DRM CRTC
+ * @mode: DRM display mode which userspace requested
+ * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
+ * @x: x offset of the CRTC scanout area on the underlying framebuffer
+ * @y: y offset of the CRTC scanout area on the underlying framebuffer
+ * @old_fb: previous framebuffer
+ *
+ * This function implements a callback useable as the ->mode_set callback
+ * required by the crtc helpers. Besides the atomic plane helper functions for
+ * the primary plane the driver must also provide the ->mode_set_nofb callback
+ * to set up the crtc.
+ *
+ * This is a transitional helper useful for converting drivers to the atomic
+ * interfaces.
+ */
+int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
+			     struct drm_display_mode *adjusted_mode, int x, int y,
+			     struct drm_framebuffer *old_fb)
+{
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	int ret;
+
+	if (crtc->funcs->atomic_duplicate_state)
+		crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	else if (crtc->state)
+		crtc_state = kmemdup(crtc->state, sizeof(*crtc_state),
+				     GFP_KERNEL);
+	else
+		crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+	if (!crtc_state)
+		return -ENOMEM;
+
+	crtc_state->enable = true;
+	crtc_state->planes_changed = true;
+	drm_mode_copy(&crtc_state->mode, mode);
+	drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
+
+	if (crtc_funcs->atomic_check) {
+		ret = crtc_funcs->atomic_check(crtc, crtc_state);
+		if (ret) {
+			kfree(crtc_state);
+
+			return ret;
+		}
+	}
+
+	swap(crtc->state, crtc_state);
+
+	crtc_funcs->mode_set_nofb(crtc);
+
+	if (crtc_state) {
+		if (crtc->funcs->atomic_destroy_state)
+			crtc->funcs->atomic_destroy_state(crtc, crtc_state);
+		else
+			kfree(crtc_state);
+	}
+
+	return drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
+}
+EXPORT_SYMBOL(drm_helper_crtc_mode_set);
+
+/**
+ * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
+ * @crtc: DRM CRTC
+ * @x: x offset of the CRTC scanout area on the underlying framebuffer
+ * @y: y offset of the CRTC scanout area on the underlying framebuffer
+ * @old_fb: previous framebuffer
+ *
+ * This function implements a callback useable as the ->mode_set_base used
+ * required by the crtc helpers. The driver must provide the atomic plane helper
+ * functions for the primary plane.
+ *
+ * This is a transitional helper useful for converting drivers to the atomic
+ * interfaces.
+ */
+int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+				  struct drm_framebuffer *old_fb)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_plane *plane = crtc->primary;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = crtc;
+	plane_state->fb = crtc->primary->fb;
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_h = crtc->mode.vdisplay;
+	plane_state->crtc_w = crtc->mode.hdisplay;
+	plane_state->src_x = x << 16;
+	plane_state->src_y = y << 16;
+	plane_state->src_h = crtc->mode.vdisplay << 16;
+	plane_state->src_w = crtc->mode.hdisplay << 16;
+
+	return drm_plane_helper_commit(plane, plane_state, old_fb);
+}
+EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 45aa8c98e3fb..40ecb2c6e858 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -370,9 +370,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 }
 EXPORT_SYMBOL(drm_crtc_init);
 
-static int
-plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
-	     struct drm_framebuffer *old_fb)
+int drm_plane_helper_commit(struct drm_plane *plane,
+			    struct drm_plane_state *plane_state,
+			    struct drm_framebuffer *old_fb)
 {
 	struct drm_plane_helper_funcs *plane_funcs;
 	struct drm_crtc *crtc[2];
@@ -497,7 +497,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	plane_state->src_h = src_h;
 	plane_state->src_w = src_w;
 
-	return plane_commit(plane, plane_state, plane->fb);
+	return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
 EXPORT_SYMBOL(drm_plane_helper_update);
 
@@ -536,6 +536,6 @@ int drm_plane_helper_disable(struct drm_plane *plane)
 	plane_state->crtc = NULL;
 	plane_state->fb = NULL;
 
-	return plane_commit(plane, plane_state, plane->fb);
+	return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
 EXPORT_SYMBOL(drm_plane_helper_disable);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index d0068b7af678..77ff8992a3b7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -230,6 +230,7 @@ struct drm_atomic_state;
  * struct drm_crtc_state - mutable crtc state
  * @enable: whether the CRTC should be enabled, gates all other state
  * @planes_changed: for use by helpers and drivers when computing state updates
+ * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
  * @event: optional pointer to a DRM event to signal upon completion of the
  * 	state update
@@ -241,6 +242,9 @@ struct drm_crtc_state {
 	/* computed state bits used by helpers and drivers */
 	bool planes_changed : 1;
 
+	/* adjusted_mode: for use by helpers and drivers */
+	struct drm_display_mode adjusted_mode;
+
 	struct drm_display_mode mode;
 
 	struct drm_pending_vblank_event *event;
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index adec48b27aa5..7adbb65ea8ae 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -68,6 +68,7 @@ struct drm_crtc_helper_funcs {
 	int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
 			struct drm_display_mode *adjusted_mode, int x, int y,
 			struct drm_framebuffer *old_fb);
+	void (*mode_set_nofb)(struct drm_crtc *crtc);
 
 	/* Move the crtc on the current fb to the given position *optional* */
 	int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
@@ -167,6 +168,12 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
 
 extern void drm_helper_resume_force_mode(struct drm_device *dev);
 
+int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
+			     struct drm_display_mode *adjusted_mode, int x, int y,
+			     struct drm_framebuffer *old_fb);
+int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+				  struct drm_framebuffer *old_fb);
+
 /* drm_probe_helper.c */
 extern int drm_helper_probe_single_connector_modes(struct drm_connector
 						   *connector, uint32_t maxX,
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index 8a0709704af0..62acb3c940b4 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -102,4 +102,8 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 			    uint32_t src_w, uint32_t src_h);
 int drm_plane_helper_disable(struct drm_plane *plane);
 
+/* For use by drm_crtc_helper.c */
+int drm_plane_helper_commit(struct drm_plane *plane,
+			    struct drm_plane_state *plane_state,
+			    struct drm_framebuffer *old_fb);
 #endif
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (8 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 09/17] drm/crtc-helper: Transitional functions using " Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-05 18:53   ` Sean Paul
  2014-11-02 13:19 ` [PATCH 11/17] drm/atomic-helper: implementatations for legacy interfaces Daniel Vetter
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

So this is finally the integration of the crtc and plane helper
interfaces into the atomic helper functions.

In the check function we now have a few steps:

- First we update the output routing and figure out which crtcs need a
  full mode set. Suitable encoders are selected using ->best_encoder,
  with the same semantics as the crtc helpers of implicitly disabling
  all connectors currently using the encoder.

- Then we pull all other connectors into the state update which feed
  from a crtc which changes. This must be done do catch mode changes
  and similar updates - atomic updates are differences on top of the
  current state.

- Then we call all the various ->mode_fixup to compute the adjusted
  mode. Note that here we have a slight semantic difference compared
  to the crtc helpers: We have not yet updated the encoder->crtc link
  when calling the encoder's ->mode_fixup function. But that's a
  requirement when converting to atomic since we want to prepare the
  entire state completely contained with the over drm_atomic_state
  structure. So this must be carefully checked when converting drivers
  over to atomic helpers.

- Finally we do call the atomic_check functions on planes and crtcs.

The commit function is also quite a beast:

- The only step that can fail is done first, namely pinning the
  framebuffers. After that we cross the point of no return, an async
  commit would push all that into the worker thread.

- The disabling of encoders and connectors is a bit tricky, since
  depending upon the final state we need to select different crtc
  helper functions.

- Software tracking is a bit clarified compared to the crtc helpers:
  We commit the software state before starting to touch the hardware,
  like crtc helpers. But since we just swap them we still have the old
  state (i.e. the current hw state) around, which is really handy to
  write simple disable functions. So no more
  drm_crtc_helper_disable_all_unused_functions kind of fun because
  we're leaving unused crtcs/encoders behind. Everything gets shut
  down in-order now, which is one of the key differences of the i915
  helpers compared to crtc helpers and a really nice additional
  guarantee.

- Like with the plane helpers the atomic commit function waits for one
  vblank to pass before calling the framebuffer cleanup function.

Compared to Rob's helper approach there's a bunch of upsides:

- All the interfaces which can fail are called in the ->check hook
  (i.e. ->best_match and the various ->mode_fixup hooks). This means
  that drivers can just reuse those functions and don't need to move
  everything into ->atomic_check callbacks. If drivers have no need
  for additional constraint checking beyong their existing crtc
  helper callbacks they don't need to do anything.

- The actual commit operation is properly stage: First we prepare
  framebuffers, which can potentially still fail (due to memory
  exhausting). This is important for the async case, where this must
  be done synchronously to correctly return errors.

- The output configuration changes (done with crtc helper functions)
  and the plane update (using atomic plane helpers) are correctly
  interleaved: First we shut down any crtcs that need changing, then
  we update planes and finally we enable everything again. Hardware
  without GO bits must be more careful with ordering, which this
  sequence enables.

- Also for hardware with shared output resources (like display PLLs)
  we first must shut down the old configuration before we can enable
  the new one. Otherwise we can hit an impossible intermediate state
  where there's not enough PLLs (which is the point behind atomic
  updates).

v2:
- Ensure that users of ->check update crtc_state->enable correctly.
- Update the legacy state in crtc/plane structures. Eventually we want
  to remove that, but for now the drm core still expects this (especially
  the plane->fb pointer).

v3: A few changes for better async handling:

- Reorder the software side state commit so that it happens all before
  we touch the hardware. This way async support becomes very easy
  since we can punt all the actual hw touching to a worker thread. And
  as long as we synchronize with that thread (flushing or cancelling,
  depending upon what the driver can handle) before we commit the next
  software state there's no need for any locking in the worker thread
  at all. Which greatly simplifies things.

  And as long as we synchronize with all relevant threads we can have
  a lot of them (e.g. per-crtc for per-crtc updates) running in
  parallel.

- Expose pre/post plane commit steps separately. We need to expose the
  actual hw commit step anyway for drivers to be able to implement
  asynchronous commit workers. But if we expose pre/post and plane
  commit steps individually we allow drivers to selectively use atomic
  helpers.

- I've forgotten to call encoder/bridge ->mode_set functions, fix
  this.

v4: Add debug output and fix a mixup between current and new state
that resulted in crtcs not getting updated correctly. And in an
Oops ...

v5:
- Be kind to driver writers in the vblank wait functions.. if thing
  aren't working yet, and vblank irq will never come, then let's not
  block forever.. especially under console-lock.
- Correctly clear connector_state->best_encoder when disabling.
  Spotted while trying to understand a report from Rob Clark.
- Only steal encoder if it actually changed, otherwise hilarity ensues
  if we steal from the current connector and so set the ->crtc pointer
  unexpectedly to NULL. Reported by Rob Clark.
- Bail out in disable_outputs if an output currently doesn't have a
  best_encoder - this means it's already disabled.

v6: Fixupe kerneldoc as reported by Paulo. And also fix up kerneldoc
in drm_crtc.h.

v7: Take ownership of the atomic state and clean it up with
drm_atomic_state_free().

v8 Various improvements all over:
- Polish code comments and kerneldoc.
- Improve debug output to make sure all failure cases are logged.
- Treat enabled crtc with no connectors as invalid input from userspace.
- Don't ignore the return value from mode_fixup().

v9:
- Improve debug output for crtc_state->mode_changed.

v10:
- Fixup the vblank waiting code to properly balance the vblank_get/put
  calls.
- Better comments when checking/computing crtc->mode_changed

v11: Fixup the encoder stealing logic: We can't look at encoder->crtc
since that's not in the atomic state structures and might be updated
asynchronously in and async commit. Instead we need to inspect all the
connector states and check whether the encoder is currently in used
and if so, on which crtc.

Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 692 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_helper.c   |   1 +
 include/drm/drm_atomic_helper.h     |   8 +
 include/drm/drm_crtc.h              |  10 +
 4 files changed, 711 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 55a8eb2678b0..887e1971c915 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -29,6 +29,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 static void
 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
@@ -57,6 +58,327 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
 	}
 }
 
+static struct drm_crtc *
+get_current_crtc_for_encoder(struct drm_device *dev,
+			     struct drm_encoder *encoder)
+{
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_connector *connector;
+
+	WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->best_encoder != encoder)
+			continue;
+
+		return connector->state->crtc;
+	}
+
+	return NULL;
+}
+
+static int
+steal_encoder(struct drm_atomic_state *state,
+	      struct drm_encoder *encoder,
+	      struct drm_crtc *encoder_crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_crtc_state *crtc_state;
+	struct drm_connector *connector;
+	struct drm_connector_state *connector_state;
+
+	/*
+	 * We can only steal an encoder coming from a connector, which means we
+	 * must already hold the connection_mutex.
+	 */
+	WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
+	DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n",
+		      encoder->base.id, encoder->name,
+		      encoder_crtc->base.id);
+
+	crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	crtc_state->mode_changed = true;
+
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->best_encoder != encoder)
+			continue;
+
+		DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n",
+			      connector->base.id,
+			      connector->name);
+
+		connector_state = drm_atomic_get_connector_state(state,
+								 connector);
+		if (IS_ERR(connector_state))
+			return PTR_ERR(connector_state);
+
+		connector_state->crtc = NULL;
+		connector_state->best_encoder = NULL;
+	}
+
+	return 0;
+}
+
+static int
+update_connector_routing(struct drm_atomic_state *state, int conn_idx)
+{
+	struct drm_connector_helper_funcs *funcs;
+	struct drm_encoder *new_encoder;
+	struct drm_connector *connector;
+	struct drm_connector_state *connector_state;
+	struct drm_crtc_state *crtc_state;
+	int idx, ret;
+
+	connector = state->connectors[conn_idx];
+	connector_state = state->connector_states[conn_idx];
+
+	if (!connector)
+		return 0;
+
+	DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n",
+			connector->base.id,
+			connector->name);
+
+	if (connector->state->crtc != connector_state->crtc) {
+		if (connector->state->crtc) {
+			idx = drm_crtc_index(connector->state->crtc);
+
+			crtc_state = state->crtc_states[idx];
+			crtc_state->mode_changed = true;
+		}
+
+		if (connector_state->crtc) {
+			idx = drm_crtc_index(connector_state->crtc);
+
+			crtc_state = state->crtc_states[idx];
+			crtc_state->mode_changed = true;
+		}
+	}
+
+	if (!connector_state->crtc) {
+		DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n",
+				connector->base.id,
+				connector->name);
+
+		connector_state->best_encoder = NULL;
+
+		return 0;
+	}
+
+	funcs = connector->helper_private;
+	new_encoder = funcs->best_encoder(connector);
+
+	if (!new_encoder) {
+		DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n",
+			      connector->base.id,
+			      connector->name);
+		return -EINVAL;
+	}
+
+	if (new_encoder != connector_state->best_encoder) {
+		struct drm_crtc *encoder_crtc;
+
+		encoder_crtc = get_current_crtc_for_encoder(state->dev,
+							    new_encoder);
+
+		if (encoder_crtc) {
+			ret = steal_encoder(state, new_encoder, encoder_crtc);
+			if (ret) {
+				DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n",
+					      connector->base.id,
+					      connector->name);
+				return ret;
+			}
+		}
+
+		connector_state->best_encoder = new_encoder;
+		idx = drm_crtc_index(connector_state->crtc);
+
+		crtc_state = state->crtc_states[idx];
+		crtc_state->mode_changed = true;
+	}
+
+	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
+		      connector->base.id,
+		      connector->name,
+		      new_encoder->base.id,
+		      new_encoder->name,
+		      connector_state->crtc->base.id);
+
+	return 0;
+}
+
+static int
+mode_fixup(struct drm_atomic_state *state)
+{
+	int ncrtcs = state->dev->mode_config.num_crtc;
+	int nconnectors = state->dev->mode_config.num_connector;
+	struct drm_crtc_state *crtc_state;
+	struct drm_connector_state *conn_state;
+	int i;
+	bool ret;
+
+	for (i = 0; i < ncrtcs; i++) {
+		crtc_state = state->crtc_states[i];
+
+		if (!crtc_state || !crtc_state->mode_changed)
+			continue;
+
+		drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode);
+	}
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_encoder_helper_funcs *funcs;
+		struct drm_encoder *encoder;
+
+		conn_state = state->connector_states[i];
+
+		if (!conn_state)
+			continue;
+
+		WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc);
+
+		if (!conn_state->crtc || !conn_state->best_encoder)
+			continue;
+
+		crtc_state =
+			state->crtc_states[drm_crtc_index(conn_state->crtc)];
+
+		/*
+		 * Each encoder has at most one connector (since we always steal
+		 * it away), so we won't call ->mode_fixup twice.
+		 */
+		encoder = conn_state->best_encoder;
+		funcs = encoder->helper_private;
+
+		if (encoder->bridge && encoder->bridge->funcs->mode_fixup) {
+			ret = encoder->bridge->funcs->mode_fixup(
+					encoder->bridge, &crtc_state->mode,
+					&crtc_state->adjusted_mode);
+			if (!ret) {
+				DRM_DEBUG_KMS("Bridge fixup failed\n");
+				return -EINVAL;
+			}
+		}
+
+
+		ret = funcs->mode_fixup(encoder, &crtc_state->mode,
+					&crtc_state->adjusted_mode);
+		if (!ret) {
+			DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
+				      encoder->base.id, encoder->name);
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc;
+
+		crtc_state = state->crtc_states[i];
+		crtc = state->crtcs[i];
+
+		if (!crtc_state || !crtc_state->mode_changed)
+			continue;
+
+		funcs = crtc->helper_private;
+		ret = funcs->mode_fixup(crtc, &crtc_state->mode,
+					&crtc_state->adjusted_mode);
+		if (!ret) {
+			DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n",
+				      crtc->base.id);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int
+drm_atomic_helper_check_prepare(struct drm_device *dev,
+				struct drm_atomic_state *state)
+{
+	int ncrtcs = dev->mode_config.num_crtc;
+	int nconnectors = dev->mode_config.num_connector;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	int i, ret;
+
+	for (i = 0; i < ncrtcs; i++) {
+		crtc = state->crtcs[i];
+		crtc_state = state->crtc_states[i];
+
+		if (!crtc)
+			continue;
+
+		if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) {
+			DRM_DEBUG_KMS("[CRTC:%d] mode changed\n",
+				      crtc->base.id);
+			crtc_state->mode_changed = true;
+		}
+
+		if (crtc->state->enable != crtc_state->enable) {
+			DRM_DEBUG_KMS("[CRTC:%d] state changed\n",
+				      crtc->base.id);
+			crtc_state->mode_changed = true;
+		}
+	}
+
+	for (i = 0; i < nconnectors; i++) {
+		/*
+		 * This only sets crtc->mode_changed for routing changes,
+		 * drivers must set crtc->mode_changed themselves when connector
+		 * properties need to be updated.
+		 */
+		ret = update_connector_routing(state, i);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * After all the routing has been prepared we need to add in any
+	 * connector which is itself unchanged, but who's crtc changes it's
+	 * configuration. This must be done before calling mode_fixup in case a
+	 * crtc only changed its mode but has the same set of connectors.
+	 */
+	for (i = 0; i < ncrtcs; i++) {
+
+		crtc = state->crtcs[i];
+		crtc_state = state->crtc_states[i];
+
+		if (!crtc)
+			continue;
+
+		if (crtc_state->mode_changed) {
+			bool has_connectors;
+
+			DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
+				      crtc->base.id,
+				      crtc_state->enable ? 'y' : 'n');
+
+			ret = drm_atomic_add_affected_connectors(state, crtc);
+			if (ret < 0)
+				return ret;
+
+			has_connectors = drm_atomic_connectors_for_crtc(state,
+									crtc);
+
+			if (crtc_state->enable != has_connectors) {
+				DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n",
+					      crtc->base.id);
+
+				return -EINVAL;
+			}
+		}
+	}
+
+	return mode_fixup(state);
+}
+
 /**
  * drm_atomic_helper_check - validate state object
  * @dev: DRM device
@@ -78,6 +400,10 @@ int drm_atomic_helper_check(struct drm_device *dev,
 	int ncrtcs = dev->mode_config.num_crtc;
 	int i, ret = 0;
 
+	ret = drm_atomic_helper_check_prepare(dev, state);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < nplanes; i++) {
 		struct drm_plane_helper_funcs *funcs;
 		struct drm_plane *plane = state->planes[i];
@@ -125,6 +451,372 @@ int drm_atomic_helper_check(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
 
+static void
+disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+	int ncrtcs = old_state->dev->mode_config.num_crtc;
+	int nconnectors = old_state->dev->mode_config.num_connector;
+	int i;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *old_conn_state;
+		struct drm_connector *connector;
+		struct drm_encoder_helper_funcs *funcs;
+		struct drm_encoder *encoder;
+
+		old_conn_state = old_state->connector_states[i];
+		connector = old_state->connectors[i];
+
+		/* Shut down everything that's in the changeset and currently
+		 * still on. So need to check the old, saved state. */
+		if (!old_conn_state || !old_conn_state->crtc)
+			continue;
+
+		encoder = connector->state->best_encoder;
+
+		if (!encoder)
+			continue;
+
+		funcs = encoder->helper_private;
+
+		/*
+		 * Each encoder has at most one connector (since we always steal
+		 * it away), so we won't call call disable hooks twice.
+		 */
+		if (encoder->bridge)
+			encoder->bridge->funcs->disable(encoder->bridge);
+
+		/* Right function depends upon target state. */
+		if (connector->state->crtc)
+			funcs->prepare(encoder);
+		else if (funcs->disable)
+			funcs->disable(encoder);
+		else
+			funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
+
+		if (encoder->bridge)
+			encoder->bridge->funcs->post_disable(encoder->bridge);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc;
+
+		crtc = old_state->crtcs[i];
+
+		/* Shut down everything that needs a full modeset. */
+		if (!crtc || !crtc->state->mode_changed)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		/* Right function depends upon target state. */
+		if (crtc->state->enable)
+			funcs->prepare(crtc);
+		else if (funcs->disable)
+			funcs->disable(crtc);
+		else
+			funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+	}
+}
+
+static void
+set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+	int nconnectors = dev->mode_config.num_connector;
+	int ncrtcs = old_state->dev->mode_config.num_crtc;
+	int i;
+
+	/* clear out existing links */
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+
+		connector = old_state->connectors[i];
+
+		if (!connector || !connector->encoder)
+			continue;
+
+		WARN_ON(!connector->encoder->crtc);
+
+		connector->encoder->crtc = NULL;
+		connector->encoder = NULL;
+	}
+
+	/* set new links */
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+
+		connector = old_state->connectors[i];
+
+		if (!connector || !connector->state->crtc)
+			continue;
+
+		if (WARN_ON(!connector->state->best_encoder))
+			continue;
+
+		connector->encoder = connector->state->best_encoder;
+		connector->encoder->crtc = connector->state->crtc;
+	}
+
+	/* set legacy state in the crtc structure */
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc;
+
+		crtc = old_state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->mode = crtc->state->mode;
+		crtc->enabled = crtc->state->enable;
+		crtc->x = crtc->primary->state->src_x >> 16;
+		crtc->y = crtc->primary->state->src_y >> 16;
+	}
+}
+
+static void
+crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+	int ncrtcs = old_state->dev->mode_config.num_crtc;
+	int nconnectors = old_state->dev->mode_config.num_connector;
+	int i;
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc;
+
+		crtc = old_state->crtcs[i];
+
+		if (!crtc || !crtc->state->mode_changed)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		if (crtc->state->enable)
+			funcs->mode_set_nofb(crtc);
+	}
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+		struct drm_crtc_state *new_crtc_state;
+		struct drm_encoder_helper_funcs *funcs;
+		struct drm_encoder *encoder;
+		struct drm_display_mode *mode, *adjusted_mode;
+
+		connector = old_state->connectors[i];
+
+		if (!connector || !connector->state->best_encoder)
+			continue;
+
+		encoder = connector->state->best_encoder;
+		funcs = encoder->helper_private;
+		new_crtc_state = connector->state->crtc->state;
+		mode = &new_crtc_state->mode;
+		adjusted_mode = &new_crtc_state->adjusted_mode;
+
+		/*
+		 * Each encoder has at most one connector (since we always steal
+		 * it away), so we won't call call mode_set hooks twice.
+		 */
+		funcs->mode_set(encoder, mode, adjusted_mode);
+
+		if (encoder->bridge && encoder->bridge->funcs->mode_set)
+			encoder->bridge->funcs->mode_set(encoder->bridge,
+							 mode, adjusted_mode);
+	}
+}
+
+/**
+ * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates
+ * @dev: DRM device
+ * @state: atomic state
+ *
+ * This function commits the modeset changes that need to be committed before
+ * updating planes. It shuts down all the outputs that need to be shut down and
+ * prepares them (if requried) with the new mode.
+ */
+void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
+					 struct drm_atomic_state *state)
+{
+	disable_outputs(dev, state);
+	set_routing_links(dev, state);
+	crtc_set_mode(dev, state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes);
+
+/**
+ * drm_atomic_helper_commit_post_planes - modeset commit after plane updates
+ * @dev: DRM device
+ * @old_state: atomic state object with old state structures
+ *
+ * This function commits the modeset changes that need to be committed after
+ * updating planes: It enables all the outputs with the new configuration which
+ * had to be turned off for the update.
+ */
+void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
+					  struct drm_atomic_state *old_state)
+{
+	int ncrtcs = old_state->dev->mode_config.num_crtc;
+	int nconnectors = old_state->dev->mode_config.num_connector;
+	int i;
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc_helper_funcs *funcs;
+		struct drm_crtc *crtc;
+
+		crtc = old_state->crtcs[i];
+
+		/* Need to filter out CRTCs where only planes change. */
+		if (!crtc || !crtc->state->mode_changed)
+			continue;
+
+		funcs = crtc->helper_private;
+
+		if (crtc->state->enable)
+			funcs->commit(crtc);
+	}
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+		struct drm_encoder_helper_funcs *funcs;
+		struct drm_encoder *encoder;
+
+		connector = old_state->connectors[i];
+
+		if (!connector || !connector->state->best_encoder)
+			continue;
+
+		encoder = connector->state->best_encoder;
+		funcs = encoder->helper_private;
+
+		/*
+		 * Each encoder has at most one connector (since we always steal
+		 * it away), so we won't call call enable hooks twice.
+		 */
+		if (encoder->bridge)
+			encoder->bridge->funcs->pre_enable(encoder->bridge);
+
+		funcs->commit(encoder);
+
+		if (encoder->bridge)
+			encoder->bridge->funcs->enable(encoder->bridge);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
+
+static void
+wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *old_crtc_state;
+	int ncrtcs = old_state->dev->mode_config.num_crtc;
+	int i, ret;
+
+	for (i = 0; i < ncrtcs; i++) {
+		crtc = old_state->crtcs[i];
+		old_crtc_state = old_state->crtc_states[i];
+
+		if (!crtc)
+			continue;
+
+		/* No one cares about the old state, so abuse it for tracking
+		 * and store whether we hold a vblank reference (and should do a
+		 * vblank wait) in the ->enable boolean. */
+		old_crtc_state->enable = false;
+
+		if (!crtc->state->enable)
+			continue;
+
+		ret = drm_crtc_vblank_get(crtc);
+		if (ret != 0)
+			continue;
+
+		old_crtc_state->enable = true;
+		old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		crtc = old_state->crtcs[i];
+		old_crtc_state = old_state->crtc_states[i];
+
+		if (!crtc || !old_crtc_state->enable)
+			continue;
+
+		ret = wait_event_timeout(dev->vblank[i].queue,
+				old_crtc_state->last_vblank_count !=
+					drm_vblank_count(dev, i),
+				msecs_to_jiffies(50));
+
+		drm_crtc_vblank_put(crtc);
+	}
+}
+
+/**
+ * drm_atomic_helper_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a with drm_atomic_helper_check() pre-validated state
+ * object. This can still fail when e.g. the framebuffer reservation fails. For
+ * now this doesn't implement asynchronous commits.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+int drm_atomic_helper_commit(struct drm_device *dev,
+			     struct drm_atomic_state *state,
+			     bool async)
+{
+	int ret;
+
+	if (async)
+		return -EBUSY;
+
+	ret = drm_atomic_helper_prepare_planes(dev, state);
+	if (ret)
+		return ret;
+
+	/*
+	 * This is the point of no return - everything below never fails except
+	 * when the hw goes bonghits. Which means we can commit the new state on
+	 * the software side now.
+	 */
+
+	drm_atomic_helper_swap_state(dev, state);
+
+	/*
+	 * Everything below can be run asynchronously withou the need to grab
+	 * any modeset locks at all under one conditions: It must be guaranteed
+	 * that the asynchronous work has either been cancelled (if the driver
+	 * supports it, which at least requires that the framebuffers get
+	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+	 * before the new state gets committed on the software side with
+	 * drm_atomic_helper_swap_state().
+	 *
+	 * This scheme allows new atomic state updates to be prepared and
+	 * checked in parallel to the asynchronous completion of the previous
+	 * update. Which is important since compositors need to figure out the
+	 * composition of the next frame right after having submitted the
+	 * current layout.
+	 */
+
+	drm_atomic_helper_commit_pre_planes(dev, state);
+
+	drm_atomic_helper_commit_planes(dev, state);
+
+	drm_atomic_helper_commit_post_planes(dev, state);
+
+	wait_for_vblanks(dev, state);
+
+	drm_atomic_helper_cleanup_planes(dev, state);
+
+	drm_atomic_state_free(state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit);
+
 /**
  * drm_atomic_helper_prepare_planes - prepare plane resources after commit
  * @dev: DRM device
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 95ecbb131053..46728a8ac622 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -927,6 +927,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
 
 	crtc_state->enable = true;
 	crtc_state->planes_changed = true;
+	crtc_state->mode_changed = true;
 	drm_mode_copy(&crtc_state->mode, mode);
 	drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
 
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 79938c62e7ad..9781ce739e10 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -30,6 +30,14 @@
 
 int drm_atomic_helper_check(struct drm_device *dev,
 			    struct drm_atomic_state *state);
+int drm_atomic_helper_commit(struct drm_device *dev,
+			     struct drm_atomic_state *state,
+			     bool async);
+
+void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
+					 struct drm_atomic_state *state);
+void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
+					  struct drm_atomic_state *old_state);
 
 int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 				     struct drm_atomic_state *state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 77ff8992a3b7..ddff25eb34d4 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -229,6 +229,9 @@ struct drm_atomic_state;
 /**
  * struct drm_crtc_state - mutable crtc state
  * @enable: whether the CRTC should be enabled, gates all other state
+ * @mode_changed: for use by helpers and drivers when computing state updates
+ * @last_vblank_count: for helpers and drivers to capture the vblank of the
+ * 	update to ensure framebuffer cleanup isn't done too early
  * @planes_changed: for use by helpers and drivers when computing state updates
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
@@ -241,6 +244,10 @@ struct drm_crtc_state {
 
 	/* computed state bits used by helpers and drivers */
 	bool planes_changed : 1;
+	bool mode_changed : 1;
+
+	/* last_vblank_count: for vblank waits before cleanup */
+	u32 last_vblank_count;
 
 	/* adjusted_mode: for use by helpers and drivers */
 	struct drm_display_mode adjusted_mode;
@@ -426,11 +433,14 @@ struct drm_crtc {
 /**
  * struct drm_connector_state - mutable connector state
  * @crtc: crtc to connect connector to, NULL if disabled
+ * @best_encoder: can be used by helpers and drivers to select the encoder
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_connector_state {
 	struct drm_crtc *crtc;
 
+	struct drm_encoder *best_encoder;
+
 	struct drm_atomic_state *state;
 };
 
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 11/17] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (9 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 22:08   ` [PATCH] " Daniel Vetter
  2014-11-02 13:19 ` [PATCH 12/17] drm/atomic: Integrate fence support Daniel Vetter
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Well, except page_flip since that requires async commit, which isn't
there yet.

For the functions which changes planes there's a bit of trickery
involved to keep the fb refcounting working. But otherwise fairly
straight-forward atomic updates.

The property setting functions are still a bit incomplete. Once we
have generic properties (e.g. rotation, but also all the properties
needed by the atomic ioctl) we need to filter those out and parse them
in the helper. Preferrably with the same function as used by the real
atomic ioctl implementation.

v2: Fixup kerneldoc, reported by Paulo.

v3: Add missing EXPORT_SYMBOL.

v4: We need to look at the crtc of the modeset, not some random
leftover one from a previous loop when udpating the connector->crtc
routing. Also push some local variables into inner loops to avoid
these kinds of bugs.

v5: Adjust semantics - drivers now own the atomic state upon
successfully synchronous commit.

v6: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v7:
- Improve comments.
- Filter out the crtc of the ->set_config call when recomputing
  crtc_state->enabled: We should compute the same state, but not doing
  so will give us a good chance to catch bugs and inconsistencies -
  the atomic helper's atomic_check function re-validates this again.
- Fix the set_config implementation logic when disabling the crtc: We
  still need to update the output routing to disable all the
  connectors properly in the state. Caught by the atomic_check
  functions, so at least that part worked ;-) Also add some WARN_ONs
  to ensure ->set_config preconditions all apply.

v8: Fixup an embarrassing h/vdisplay mixup.

Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 511 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  21 ++
 2 files changed, 532 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 887e1971c915..26fe60356a0f 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1045,3 +1045,514 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
+
+/**
+ * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_update_plane);
+
+/**
+ * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic
+ * @plane: plane to disable
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_disable_plane(struct drm_plane *plane)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	drm_atomic_set_crtc_for_plane(plane_state, NULL);
+	plane_state->fb = NULL;
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_h = 0;
+	plane_state->crtc_w = 0;
+	plane_state->src_x = 0;
+	plane_state->src_y = 0;
+	plane_state->src_h = 0;
+	plane_state->src_w = 0;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_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_connector_state *conn_state;
+	int nconnectors = state->dev->mode_config.num_connector;
+	int ncrtcs = state->dev->mode_config.num_crtc;
+	int ret, i, j;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	/* First grab all affected connector/crtc states. */
+	for (i = 0; i < set->num_connectors; i++) {
+		conn_state = drm_atomic_get_connector_state(state,
+							    set->connectors[i]);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		ret = drm_atomic_add_affected_connectors(state, crtc);
+		if (ret)
+			return ret;
+	}
+
+	/* Then recompute connector->crtc links and crtc enabling state. */
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+
+		connector = state->connectors[i];
+		conn_state = state->connector_states[i];
+
+		if (!connector)
+			continue;
+
+		if (conn_state->crtc == set->crtc)
+			conn_state->crtc = NULL;
+
+		for (j = 0; j < set->num_connectors; j++) {
+			if (set->connectors[j] == connector) {
+				conn_state->crtc = set->crtc;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+		struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+		if (!crtc && crtc != set->crtc)
+			continue;
+
+		crtc_state->enable =
+			drm_atomic_connectors_for_crtc(state, crtc);
+	}
+
+	return 0;
+}
+
+/**
+ * drm_atomic_helper_set_config - set a new config from userspace
+ * @set: mode set configuration
+ *
+ * Provides a default crtc set_config handler using the atomic driver interface.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_set_config(struct drm_mode_set *set)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc *crtc = set->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane_state *primary_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	if (!set->mode) {
+		WARN_ON(set->fb);
+		WARN_ON(set->num_connectors);
+
+		crtc_state->enable = false;
+		goto commit;
+	}
+
+	WARN_ON(!set->fb);
+	WARN_ON(!set->num_connectors);
+
+	crtc_state->enable = true;
+	drm_mode_copy(&crtc_state->mode, set->mode);
+
+	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+	if (IS_ERR(primary_state)) {
+		ret = PTR_ERR(primary_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	drm_atomic_set_crtc_for_plane(primary_state, crtc);
+	primary_state->fb = set->fb;
+	primary_state->crtc_x = 0;
+	primary_state->crtc_y = 0;
+	primary_state->crtc_h = set->mode->vdisplay;
+	primary_state->crtc_w = set->mode->hdisplay;
+	primary_state->src_x = set->x << 16;
+	primary_state->src_y = set->y << 16;
+	primary_state->src_h = set->mode->vdisplay << 16;
+	primary_state->src_w = set->mode->hdisplay << 16;
+
+commit:
+	ret = update_output_state(state, set);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	crtc->primary->old_fb = crtc->primary->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_set_config);
+
+/**
+ * drm_atomic_helper_crtc_set_property - helper for crtc prorties
+ * @crtc: DRM crtc
+ * @prorty: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
+
+/**
+ * drm_atomic_helper_plane_set_property - helper for plane prorties
+ * @plane: DRM plane
+ * @prorty: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disable handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = plane->dev->mode_config.acquire_ctx;
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = plane->funcs->atomic_set_property(plane, plane_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+/**
+ * drm_atomic_helper_connector_set_property - helper for connector prorties
+ * @connector: DRM connector
+ * @prorty: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector_state *connector_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(connector->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = connector->dev->mode_config.acquire_ctx;
+retry:
+	connector_state = drm_atomic_get_connector_state(state, connector);
+	if (IS_ERR(connector_state)) {
+		ret = PTR_ERR(connector_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = connector->funcs->atomic_set_property(connector, connector_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 9781ce739e10..8cd6fe7a48e5 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -49,4 +49,25 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
 void drm_atomic_helper_swap_state(struct drm_device *dev,
 				  struct drm_atomic_state *state);
 
+/* implementations for legacy interfaces */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h);
+int drm_atomic_helper_disable_plane(struct drm_plane *plane);
+int drm_atomic_helper_set_config(struct drm_mode_set *set);
+
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+					struct drm_property *property,
+					uint64_t val);
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* [PATCH 12/17] drm/atomic: Integrate fence support
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (10 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 11/17] drm/atomic-helper: implementatations for legacy interfaces Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-06 17:43   ` [Intel-gfx] " Sean Paul
  2014-11-02 13:19 ` [PATCH 13/17] drm/atomic-helpers: document how to implement async commit Daniel Vetter
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter

This patch is for enabling async commits. It replaces an earlier
approach which added an async boolean paramter to the ->prepare_fb
callbacks. The idea is that prepare_fb picks up the right fence to
synchronize against, which is then used by the synchronous commit
helper. For async commits drivers can either register a callback to
the fence or simply do the synchronous wait in their async work queue.

v2: Remove unused variable.

v3: Only wait for fences after the point of no return in the part
of the commit function which can be run asynchronously. This is after
the atomic state has been swapped in, hence now check
plane->state->fence.

Also add a WARN_ON to make sure we don't try to wait on a fence when
there's no fb, just as a sanity check.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 23 +++++++++++++++++++++++
 include/drm/drm_crtc.h              |  3 +++
 2 files changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 26fe60356a0f..afdc376aa7e7 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -30,6 +30,7 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <linux/fence.h>
 
 static void
 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
@@ -704,6 +705,26 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
 
+static void wait_for_fences(struct drm_device *dev,
+			    struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane || !plane->state->fence)
+			continue;
+
+		WARN_ON(!plane->state->fb);
+
+		fence_wait(plane->state->fence, false);
+		fence_put(plane->state->fence);
+		plane->state->fence = NULL;
+	}
+}
+
 static void
 wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
@@ -801,6 +822,8 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 	 * current layout.
 	 */
 
+	wait_for_fences(dev, state);
+
 	drm_atomic_helper_commit_pre_planes(dev, state);
 
 	drm_atomic_helper_commit_planes(dev, state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index ddff25eb34d4..5c34665ebb9d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -42,6 +42,7 @@ struct drm_object_properties;
 struct drm_file;
 struct drm_clip_rect;
 struct device_node;
+struct fence;
 
 #define DRM_MODE_OBJECT_CRTC 0xcccccccc
 #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
@@ -659,6 +660,7 @@ struct drm_connector {
  * struct drm_plane_state - mutable plane state
  * @crtc: currently bound CRTC, NULL if disabled
  * @fb: currently bound fb
+ * @fence: optional fence to wait for before scanning out @fb
  * @crtc_x: left position of visible portion of plane on crtc
  * @crtc_y: upper position of visible portion of plane on crtc
  * @crtc_w: width of visible portion of plane on crtc
@@ -674,6 +676,7 @@ struct drm_connector {
 struct drm_plane_state {
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb;
+	struct fence *fence;
 
 	/* Signed dest location allows it to be partially off screen */
 	int32_t crtc_x, crtc_y;
-- 
2.1.1

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

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

* [PATCH 13/17] drm/atomic-helpers: document how to implement async commit
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (11 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 12/17] drm/atomic: Integrate fence support Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-06 17:43   ` Sean Paul
  2014-11-02 13:19 ` [PATCH 14/17] drm/atomic-helper: implement ->page_flip Daniel Vetter
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

No helper function to do it all yet provided since no driver has
support for driver core fences yet. Which we'd need to make the
implementation really generic.

v2: Clarify async howto a bit per the discussion With Rob Clark.

Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index afdc376aa7e7..92ae34bde44d 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -841,6 +841,44 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 EXPORT_SYMBOL(drm_atomic_helper_commit);
 
 /**
+ * DOC: implementing async commit
+ *
+ * For now the atomic helpers don't support async commit directly. If there is
+ * real need it could be added though, using the dma-buf fence infrastructure
+ * for generic synchronization with outstanding rendering.
+ *
+ * For now drivers have to implement async commit themselves, with the following
+ * sequence being the recommended one:
+ *
+ * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function
+ * which commit needs to call which can fail, so we want to run it first and
+ * synchronously.
+ *
+ * 2. Synchronize with any outstanding asynchronous commit worker threads which
+ * might be affected the new state update. This can be done by either cancelling
+ * or flushing the work items, depending upon whether the driver can deal with
+ * cancelled updates. Note that it is important to ensure that the framebuffer
+ * cleanup is still done when cancelling.
+ *
+ * For sufficient parallelism it is recommended to have a work item per crtc
+ * (for updates which don't touch global state) and a global one. Then we only
+ * need to synchronize with the crtc work items for changed crtcs and the global
+ * work item, which allows nice concurrent updates on disjoint sets of crtcs.
+ *
+ * 3. The software state is updated synchronously with
+ * drm_atomic_helper_swap_state. Doing this under the protection of all modeset
+ * locks means concurrent callers never see inconsistent state. And doing this
+ * while it's guaranteed that no relevant async worker runs means that async
+ * workers do not need grab any locks. Actually they must not grab locks, for
+ * otherwise the work flushing will deadlock.
+ *
+ * 4. Schedule a work item to do all subsequent steps, using the split-out
+ * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and
+ * then cleaning up the framebuffers after the old framebuffer is no longer
+ * being displayed.
+ */
+
+/**
  * drm_atomic_helper_prepare_planes - prepare plane resources after commit
  * @dev: DRM device
  * @state: atomic state object with old state structures
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 14/17] drm/atomic-helper: implement ->page_flip
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (12 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 13/17] drm/atomic-helpers: document how to implement async commit Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 22:09   ` [PATCH] " Daniel Vetter
  2014-11-06 17:43   ` [PATCH 14/17] " Sean Paul
  2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
                   ` (2 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Currently there is no way to implement async flips using atomic, that
essentially requires us to be able to cancel pending requests
mid-flight.

To be able to do that (and I guess we want this since vblank synced
updates whic opportunistically cancel still pending updates seem to be
wanted) we'd need to add a mandatory cancellation mode. Depending upon
the exact semantics we decide upon that could mean that userspace will
not get completion events, or will get them all stacked up.

So reject async updates for now. Also async updates usually means not
vblank synced at all, and I guess for drivers which want to support
this they should simply add a special pageflip handler (since usually
you need a special flip cmd to achieve this). That kind of async flip
is pretty much exclusively just used for games and benchmarks where
dropping just one frame means you'll get a headshot or something bad
like that ... And so slight amounts of tearing is acceptable.

v2: Fixup kerneldoc, reported by Paulo.

v3: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v4: Update crtc->primary->fb since ->page_flip is the only driver
callback where the core won't do this itself. We might want to fix
this inconsistency eventually.

Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 90 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  5 +++
 2 files changed, 95 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 92ae34bde44d..70bd67cf86e3 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1617,3 +1617,93 @@ backoff:
 	goto retry;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
+
+/**
+ * drm_atomic_helper_page_flip - execute a legacy page flip
+ * @crtc: DRM crtc
+ * @fb: DRM framebuffer
+ * @event: optional DRM event to signal upon completion
+ * @flags: flip flags for non-vblank sync'ed updates
+ *
+ * Provides a default page flip implementation using the atomic driver interface.
+ *
+ * Note that for now so called async page flips (i.e. updates which are not
+ * synchronized to vblank) are not supported, since the atomic interfaces have
+ * no provisions for this yet.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags)
+{
+	struct drm_plane *plane = crtc->primary;
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+		return -EINVAL;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+	crtc_state->event = event;
+
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	plane_state->fb = fb;
+
+	ret = drm_atomic_async_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful async commit. */
+	if (ret == 0) {
+		/* TODO: ->page_flip is the only driver callback where the core
+		 * doesn't update plane->fb. For now patch it up here. */
+		plane->fb = plane->state->fb;
+
+		return 0;
+	}
+
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_page_flip);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 8cd6fe7a48e5..28a2f3a815fd 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
 int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
 					struct drm_property *property,
 					uint64_t val);
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags);
+
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (13 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 14/17] drm/atomic-helper: implement ->page_flip Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-03 14:45   ` Daniel Thompson
                     ` (2 more replies)
  2014-11-02 13:19 ` [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers Daniel Vetter
  2014-11-02 13:19 ` [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb Daniel Vetter
  16 siblings, 3 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

The atomic users and helpers assume that there is always a obj->state
structure around. Which means drivers need to somehow create that at
driver load time. Also it should obviously reset hardware state, so
needs to be reset upon resume.

Finally the destroy/duplicate_state functions are an awful lot of
boilerplate if the driver doesn't need anything beyond the default
state objects.

So add helper functions for all of this.

v2: Somehow the plane/connector versions got lost in the first
version.

v3: Add kerneldoc.

v4: Make duplicate_state functions a bit more robust, which is useful
for debugging state tracking issues when transitioning to atomic.

v5: Clear temporary variables in the crtc state when duplicating it,
like ->mode_changed or ->planes_changed. If we don't do this stale
values for these might pollute the next atomic modeset.

v6: Also clear crtc_state->event in case the driver didn't (yet) clear
this out.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 154 +++++++++++++++++++++++++++++++++++-
 include/drm/drm_atomic_helper.h     |  19 +++++
 2 files changed, 170 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 70bd67cf86e3..bd38df3cbe55 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1429,7 +1429,7 @@ EXPORT_SYMBOL(drm_atomic_helper_set_config);
 /**
  * drm_atomic_helper_crtc_set_property - helper for crtc prorties
  * @crtc: DRM crtc
- * @prorty: DRM property
+ * @property: DRM property
  * @val: value of property
  *
  * Provides a default plane disablle handler using the atomic driver interface.
@@ -1493,7 +1493,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
 /**
  * drm_atomic_helper_plane_set_property - helper for plane prorties
  * @plane: DRM plane
- * @prorty: DRM property
+ * @property: DRM property
  * @val: value of property
  *
  * Provides a default plane disable handler using the atomic driver interface.
@@ -1557,7 +1557,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
 /**
  * drm_atomic_helper_connector_set_property - helper for connector prorties
  * @connector: DRM connector
- * @prorty: DRM property
+ * @property: DRM property
  * @val: value of property
  *
  * Provides a default plane disablle handler using the atomic driver interface.
@@ -1707,3 +1707,151 @@ backoff:
 	goto retry;
 }
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+
+/**
+ * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
+ * @crtc: drm CRTC
+ *
+ * Resets the atomic state for @crtc by freeing the state pointer and allocating
+ * a new empty state object.
+ */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
+{
+	kfree(crtc->state);
+	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
+
+/**
+ * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
+ * @crtc: drm CRTC
+ *
+ * Default CRTC state duplicate hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *state;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
+
+	if (state) {
+		state->mode_changed = false;
+		state->planes_changed = false;
+		state->event = NULL;
+	}
+
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
+
+/**
+ * drm_atomic_helper_crtc_destroy_state - default state destroy hook
+ * @crtc: drm CRTC
+ * @state: CRTC state object to release
+ *
+ * Default CRTC state destroy hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * drm_atomic_helper_plane_reset - default ->reset hook for planes
+ * @plane: drm plane
+ *
+ * Resets the atomic state for @plane by freeing the state pointer and
+ * allocating a new empty state object.
+ */
+void drm_atomic_helper_plane_reset(struct drm_plane *plane)
+{
+	kfree(plane->state);
+	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
+
+/**
+ * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
+ * @plane: drm plane
+ *
+ * Default plane state duplicate hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
+{
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
+
+/**
+ * drm_atomic_helper_plane_destroy_state - default state destroy hook
+ * @plane: drm plane
+ * @state: plane state object to release
+ *
+ * Default plane state destroy hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
+
+/**
+ * drm_atomic_helper_connector_reset - default ->reset hook for connectors
+ * @connector: drm connector
+ *
+ * Resets the atomic state for @connector by freeing the state pointer and
+ * allocating a new empty state object.
+ */
+void drm_atomic_helper_connector_reset(struct drm_connector *connector)
+{
+	kfree(connector->state);
+	connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+
+/**
+ * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
+ * @connector: drm connector
+ *
+ * Default connector state duplicate hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+struct drm_connector_state *
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
+{
+	if (WARN_ON(!connector->state))
+		return NULL;
+
+	return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
+
+/**
+ * drm_atomic_helper_connector_destroy_state - default state destroy hook
+ * @connector: drm connector
+ * @state: connector state object to release
+ *
+ * Default connector state destroy hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+					  struct drm_connector_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 28a2f3a815fd..67e3c4645ae0 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -74,5 +74,24 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
 				struct drm_pending_vblank_event *event,
 				uint32_t flags);
 
+/* default implementations for state handling */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state);
+
+void drm_atomic_helper_plane_reset(struct drm_plane *plane);
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state);
+
+void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+struct drm_connector_state *
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+					  struct drm_connector_state *state);
+
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (14 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-06 17:43   ` Sean Paul
  2014-11-06 20:00   ` [PATCH] " Daniel Vetter
  2014-11-02 13:19 ` [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb Daniel Vetter
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

In all cases the text requires that new drivers are converted to the
atomic interfaces.

v2: Add overview for state handling.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl      | 20 +++++++++++++++++++-
 drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_helper.c   | 20 ++++++++++++++++++++
 drivers/gpu/drm/drm_plane_helper.c  | 26 +++++++++++++++++++++++++-
 4 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index ea0ef43b19e1..5e3a11f5e941 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2324,8 +2324,25 @@ void intel_crt_init(struct drm_device *dev)
       </itemizedlist>
     </sect2>
     <sect2>
+      <title>Atomic Modeset Helper Functions Reference</title>
+      <sect3>
+	<title>Overview</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c overview
+      </sect3>
+      <sect3>
+	<title>Implementing Asynchronous Atomic Commit</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c implementing async commit
+      </sect3>
+      <sect3>
+	<title>Atomic State Reset and Initialization</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
+      </sect3>
+!Edrivers/gpu/drm/drm_atomic_helper.c
+    </sect2>
+    <sect2>
       <title>Modeset Helper Functions Reference</title>
 !Edrivers/gpu/drm/drm_crtc_helper.c
+!Pdrivers/gpu/drm/drm_crtc_helper.c overview
     </sect2>
     <sect2>
       <title>Output Probing Helper Functions Reference</title>
@@ -2379,7 +2396,8 @@ void intel_crt_init(struct drm_device *dev)
     </sect2>
     <sect2>
       <title id="drm-kms-planehelpers">Plane Helper Reference</title>
-!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
+!Edrivers/gpu/drm/drm_plane_helper.c
+!Pdrivers/gpu/drm/drm_plane_helper.c overview
     </sect2>
   </sect1>
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bd38df3cbe55..d0ca681d6326 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -32,6 +32,27 @@
 #include <drm/drm_atomic_helper.h>
 #include <linux/fence.h>
 
+/**
+ * DOC: overview
+ *
+ * This helper library provides implementations of check and commit functions on
+ * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
+ * also provides convenience implementations for the atomic state handling
+ * callbacks for drivers which don't need to subclass the drm core structures to
+ * add their own additional internal state.
+ *
+ * This library also provides default implementations for the check callback in
+ * drm_atomic_helper_check and for the commit callback with
+ * drm_atomic_helper_commit. But the individual stages and callbacks are expose
+ * to allow drivers to mix and match and e.g. use the plane helpers only
+ * together with a driver private modeset implementation.
+ *
+ * This library also provides implementations for all the legacy driver
+ * interfaces on top of the atomic interface. See drm_atomic_helper_set_config,
+ * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the
+ * various functions to implement set_property callbacks. New drivers must not
+ * implement these functions themselves but must use the provided helpers.
+ */
 static void
 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
 				struct drm_plane_state *plane_state,
@@ -1709,6 +1730,21 @@ backoff:
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
 
 /**
+ * DOC: atomic state reset and initialization
+ *
+ * Both the drm core and the atomic helpers assume that there is always the full
+ * and correct atomic software state for all connectors, CRTCs and planes
+ * available. Which is a bit a problem on driver load and also after system
+ * suspend. One way to solve this is to have a hardware state read-out
+ * infrastructure which reconstructs the full software state (e.g. the i915
+ * driver).
+ *
+ * The simpler solution is to just reset the software state to everything off,
+ * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
+ * the atomic helpers provide default reset implementations for all hooks.
+ */
+
+/**
  * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
  * @crtc: drm CRTC
  *
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 46728a8ac622..33195e9adaab 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -41,6 +41,26 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_edid.h>
 
+/**
+ * DOC: overview
+ *
+ * The CRTC modeset helper library provides a default set_config implementation
+ * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
+ * the same callbacks which drivers can use to e.g. restore the modeset
+ * configuration on resume with drm_helper_resume_force_mode().
+ *
+ * The driver callbacks are mostly compatible with the atomic modeset helpers,
+ * except for the handling of the primary plane: Atomic helpers require that the
+ * primary plane is implemented as a real standalone plane and not directly tied
+ * to the CRTC state. For easier transition this library provides functions to
+ * implement the old semantics required by the CRTC helpers using the new plane
+ * and atomic helper callbacks.
+ *
+ * Drivers are strongly urged to convert to the atomic helpers (by way of first
+ * converting to the plane helpers). New drivers must not use these functions
+ * but need to implement the atomic interface instead, potentially using the
+ * atomic helpers for that.
+ */
 MODULE_AUTHOR("David Airlie, Jesse Barnes");
 MODULE_DESCRIPTION("DRM KMS helper");
 MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 40ecb2c6e858..df69522b1f0e 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -31,6 +31,31 @@
 
 #define SUBPIXEL_MASK 0xffff
 
+/**
+ * DOC: overview
+ *
+ * This helper library has two ports. The first part has support to implement
+ * primary plane support on top of the normal CRTC configuration interface. Sinc
+ * the legacy ->set_config interface ties the primary plane together with the
+ * CRTC state this does not userspace to disable the primary plane itself. To
+ * avoid too much duplicated code use drm_plane_helper_check_update() which can
+ * be used to enforce the same restrictions as primary planes had thus. The
+ * default primary plane only expose XRBG8888 and ARGB8888 as valid pixel
+ * formats for the attached framebuffer.
+ *
+ * Drivers are highly recommended to implement proper support for primary
+ * planes, and newly merged drivers must not rely upon these transitional
+ * helpers.
+ *
+ * The second part also implements transitional helpers which allow drivers to
+ * gradually switch to the atomic helper infrastructure for plane updates. Once
+ * that switch is complete drivers shouldn't use these any longer, instead using
+ * the proper legacy implementations for update and disable plane hooks provided
+ * by the atomic helpers.
+ *
+ * Again drivers are strongly urged to switch to the new interfaces.
+ */
+
 /*
  * This is the minimal list of formats that seem to be safe for modeset use
  * with all current DRM drivers.  Most hardware can actually support more
@@ -40,7 +65,6 @@
  */
 static const uint32_t safe_modeset_formats[] = {
 	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_ARGB8888,
 };
 
 /*
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb
  2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
                   ` (15 preceding siblings ...)
  2014-11-02 13:19 ` [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers Daniel Vetter
@ 2014-11-02 13:19 ` Daniel Vetter
  2014-11-04 21:57   ` [PATCH] " Daniel Vetter
  2014-11-06 17:44   ` [PATCH 17/17] " Sean Paul
  16 siblings, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 13:19 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter

So my original plan was that the drm core refcounts framebuffers like
with the legacy ioctls. But that doesn't work for a bunch of reasons:

- State objects might live longer than until the next fb change
  happens for a plane. For example delayed cleanup work only happens
  _after_ the pageflip ioctl has completed. So this definitely doesn't
  work without the plane state holding its own refernces.

- The other issue is transition from legacy to atomic implementations,
  where the driver works under a mix of both worlds. Which means
  legacy paths might not properly update the ->fb pointer under
  plane->state->fb. Which is a bit a problem when then someone comes
  around and _does_ try to clean it up when it's long gone.

The second issue is just a bit a transition bug, since drivers should
update plane->state->fb in all the paths that aren't converted yet.
But a bit more robustness for the transition cant' hurt - we pull
similar tricks with cleaning up the old fb in the transitional helpers
already.

The pattern for drivers that transition is

	if (plane->state)
		drm_atomic_set_fb_for_plane(plane->state, plane->fb);

inserted after the fb update has logically completed at the end of
->set_config (or ->set_base/mode_set if using the crtc helpers),
->page_flip, ->update_plane or any other entry point which updates
plane->fb.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/drm_atomic.c        | 27 +++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++++++++++------
 drivers/gpu/drm/drm_crtc_helper.c   |  7 ++++---
 drivers/gpu/drm/drm_plane_helper.c  | 14 +++++++-------
 include/drm/drm_atomic.h            |  2 ++
 5 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index c6db8a48cad6..af34321b675d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -366,6 +366,33 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
 
 /**
+ * drm_atomic_set_fb_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @fb: fb to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ */
+void
+drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+			    struct drm_framebuffer *fb)
+{
+	if (plane_state->fb)
+		drm_framebuffer_unreference(plane_state->fb);
+	if (fb)
+		drm_framebuffer_reference(fb);
+	plane_state->fb = fb;
+
+	if (fb)
+		DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n",
+			      fb->base.id, plane_state);
+	else
+		DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state);
+}
+EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
+
+/**
  * drm_atomic_set_crtc_for_connector - set crtc for connector
  * @conn_state: atomic state object for the connector
  * @crtc: crtc to use for the connector
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index d0ca681d6326..a5de60faedff 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1175,7 +1175,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, crtc);
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 	plane_state->crtc_x = crtc_x;
 	plane_state->crtc_y = crtc_y;
 	plane_state->crtc_h = crtc_h;
@@ -1242,7 +1242,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, NULL);
-	plane_state->fb = NULL;
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
 	plane_state->crtc_h = 0;
@@ -1402,7 +1402,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(primary_state, crtc);
-	primary_state->fb = set->fb;
+	drm_atomic_set_fb_for_plane(primary_state, set->fb);
 	primary_state->crtc_x = 0;
 	primary_state->crtc_y = 0;
 	primary_state->crtc_h = set->mode->vdisplay;
@@ -1695,7 +1695,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, crtc);
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 
 	ret = drm_atomic_async_commit(state);
 	if (ret == -EDEADLK)
@@ -1809,6 +1809,9 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
  */
 void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 {
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
 	kfree(plane->state);
 	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
 }
@@ -1824,10 +1827,17 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
 {
+	struct drm_plane_state *state;
+
 	if (WARN_ON(!plane->state))
 		return NULL;
 
-	return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+	state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+
+	if (state && state->fb)
+		drm_framebuffer_reference(state->fb);
+
+	return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 
@@ -1840,8 +1850,11 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
  * subclassed plane state structure.
  */
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
-					  struct drm_plane_state *state)
+					   struct drm_plane_state *state)
 {
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
+
 	kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 33195e9adaab..d552708409de 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -34,11 +34,13 @@
 #include <linux/moduleparam.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 
 /**
@@ -998,15 +1000,14 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = crtc;
-	plane_state->fb = crtc->primary->fb;
+	drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
 	plane_state->crtc_h = crtc->mode.vdisplay;
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index df69522b1f0e..497104df112b 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -27,7 +27,9 @@
 #include <drm/drmP.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -462,7 +464,7 @@ fail:
 		if (plane->funcs->atomic_destroy_state)
 			plane->funcs->atomic_destroy_state(plane, plane_state);
 		else
-			kfree(plane_state);
+			drm_atomic_helper_plane_destroy_state(plane, plane_state);
 	}
 
 	return ret;
@@ -503,15 +505,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = crtc;
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 	plane_state->crtc_x = crtc_x;
 	plane_state->crtc_y = crtc_y;
 	plane_state->crtc_h = crtc_h;
@@ -550,15 +551,14 @@ int drm_plane_helper_disable(struct drm_plane *plane)
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = NULL;
-	plane_state->fb = NULL;
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
 
 	return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 753812034e71..52d92981209f 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -45,6 +45,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 
 int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 				  struct drm_crtc *crtc);
+void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+				 struct drm_framebuffer *fb);
 int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 				      struct drm_crtc *crtc);
 int
-- 
2.1.1

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

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

* [PATCH] drm: Pull drm_crtc.h into the kerneldoc template
  2014-11-02 13:19 ` [PATCH 02/17] drm: Pull drm_crtc.h into the kerneldoc template Daniel Vetter
@ 2014-11-02 19:18   ` Daniel Vetter
  2014-11-03  3:04     ` Thierry Reding
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 19:18 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

While writing atomic docs I've noticed that I don't get any errors
for my screw-ups in drm_crtc.h. Fix this immediately.

This just does the bare minimum to get starts, lots of stuff isn't
properly documented yet unfortunately.

v2: Fix adjacent spelling error Sean noticed.

Reviewed-by: Sean Paul <seanpaul@chromium.org>
Cc: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |  4 ++++
 include/drm/drm_crtc.h         | 28 ++++++++++++++--------------
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index be35bc328b77..89829ae58e97 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -1827,6 +1827,10 @@ void intel_crt_init(struct drm_device *dev)
 !Edrivers/gpu/drm/drm_crtc.c
     </sect2>
     <sect2>
+      <title>KMS Data Structures</title>
+!Iinclude/drm/drm_crtc.h
+    </sect2>
+    <sect2>
       <title>KMS Locking</title>
 !Pdrivers/gpu/drm/drm_modeset_lock.c kms locking
 !Iinclude/drm/drm_modeset_lock.h
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 44c57d2a64ec..82bb55ff41a2 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -142,8 +142,8 @@ struct drm_framebuffer_funcs {
 	int (*create_handle)(struct drm_framebuffer *fb,
 			     struct drm_file *file_priv,
 			     unsigned int *handle);
-	/**
-	 * Optinal callback for the dirty fb ioctl.
+	/*
+	 * Optional callback for the dirty fb ioctl.
 	 *
 	 * Userspace can notify the driver via this callback
 	 * that a area of the framebuffer has changed and should
@@ -226,7 +226,7 @@ struct drm_plane;
 struct drm_bridge;
 
 /**
- * drm_crtc_funcs - control CRTCs for a given device
+ * struct drm_crtc_funcs - control CRTCs for a given device
  * @save: save CRTC state
  * @restore: restore CRTC state
  * @reset: reset CRTC after state has been invalidated (e.g. resume)
@@ -290,7 +290,7 @@ struct drm_crtc_funcs {
 };
 
 /**
- * drm_crtc - central CRTC control structure
+ * struct drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
  * @mutex: per-CRTC locking
@@ -322,7 +322,7 @@ struct drm_crtc {
 	struct device_node *port;
 	struct list_head head;
 
-	/**
+	/*
 	 * crtc mutex
 	 *
 	 * This provides a read lock for the overall crtc state (mode, dpms
@@ -377,7 +377,7 @@ struct drm_crtc {
 
 
 /**
- * drm_connector_funcs - control connectors on a given device
+ * struct drm_connector_funcs - control connectors on a given device
  * @dpms: set power state (see drm_crtc_funcs above)
  * @save: save connector state
  * @restore: restore connector state
@@ -414,7 +414,7 @@ struct drm_connector_funcs {
 };
 
 /**
- * drm_encoder_funcs - encoder controls
+ * struct drm_encoder_funcs - encoder controls
  * @reset: reset state (e.g. at init or resume time)
  * @destroy: cleanup and free associated data
  *
@@ -428,7 +428,7 @@ struct drm_encoder_funcs {
 #define DRM_CONNECTOR_MAX_ENCODER 3
 
 /**
- * drm_encoder - central DRM encoder structure
+ * struct drm_encoder - central DRM encoder structure
  * @dev: parent DRM device
  * @head: list management
  * @base: base KMS object
@@ -472,7 +472,7 @@ struct drm_encoder {
 #define MAX_ELD_BYTES	128
 
 /**
- * drm_connector - central DRM connector control structure
+ * struct drm_connector - central DRM connector control structure
  * @dev: parent DRM device
  * @kdev: kernel device for sysfs attributes
  * @attr: sysfs attributes
@@ -566,7 +566,7 @@ struct drm_connector {
 };
 
 /**
- * drm_plane_funcs - driver plane control functions
+ * struct drm_plane_funcs - driver plane control functions
  * @update_plane: update the plane configuration
  * @disable_plane: shut down the plane
  * @destroy: clean up plane resources
@@ -594,7 +594,7 @@ enum drm_plane_type {
 };
 
 /**
- * drm_plane - central DRM plane control structure
+ * struct drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
  * @base: base mode object
@@ -632,7 +632,7 @@ struct drm_plane {
 };
 
 /**
- * drm_bridge_funcs - drm_bridge control functions
+ * struct drm_bridge_funcs - drm_bridge control functions
  * @attach: Called during drm_bridge_attach
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
  * @disable: Called right before encoder prepare, disables the bridge
@@ -658,7 +658,7 @@ struct drm_bridge_funcs {
 };
 
 /**
- * drm_bridge - central DRM bridge control structure
+ * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
  * @head: list management
  * @base: base mode object
@@ -679,7 +679,7 @@ struct drm_bridge {
 };
 
 /**
- * drm_mode_set - new values for a CRTC config change
+ * struct drm_mode_set - new values for a CRTC config change
  * @head: list management
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h
  2014-11-02 13:19 ` [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h Daniel Vetter
@ 2014-11-02 19:19   ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-02 19:19 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Vetter, Intel Graphics Development, Thomas Wood,
	Russell King, Daniel Vetter

On Sun, Nov 02, 2014 at 02:19:16PM +0100, Daniel Vetter wrote:
> I've tried to cc all the people who have recently added new stuff
> but forgotten to update documentation.
> 
> I've also decided not to bother documenting the massive property list
> in struct drm_mode_config. If that beast keeps on growing we might want
> to extract it into a separate structure which we won't document.
> 
> Cc: Thomas Wood <thomas.wood@intel.com>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Russell King <rmk+kernel@arm.linux.org.uk>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

Oops, I've somehow lost Sean's r-b on this and the preceeding patch.
Resent the preceeding patch since that had one small change Sean requested
and added his r-b locally to both.
-Daniel

> ---
>  include/drm/drm_crtc.h | 51 +++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 36 insertions(+), 15 deletions(-)
> 
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 21a15850a4d5..a68e02be7e37 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -231,6 +231,7 @@ struct drm_bridge;
>   * @restore: restore CRTC state
>   * @reset: reset CRTC after state has been invalidated (e.g. resume)
>   * @cursor_set: setup the cursor
> + * @cursor_set2: setup the cursor with hotspot, superseeds @cursor_set if set
>   * @cursor_move: move the cursor
>   * @gamma_set: specify color ramp for CRTC
>   * @destroy: deinit and free object
> @@ -292,11 +293,14 @@ struct drm_crtc_funcs {
>  /**
>   * struct drm_crtc - central CRTC control structure
>   * @dev: parent DRM device
> + * @port: OF node used by drm_of_find_possible_crtcs()
>   * @head: list management
>   * @mutex: per-CRTC locking
>   * @base: base KMS object for ID tracking etc.
>   * @primary: primary plane for this CRTC
>   * @cursor: cursor plane for this CRTC
> + * @cursor_x: current x position of the cursor, used for universal cursor planes
> + * @cursor_y: current y position of the cursor, used for universal cursor planes
>   * @enabled: is this CRTC enabled?
>   * @mode: current mode timings
>   * @hwmode: mode timings as programmed to hw regs
> @@ -309,10 +313,12 @@ struct drm_crtc_funcs {
>   * @gamma_size: size of gamma ramp
>   * @gamma_store: gamma ramp values
>   * @framedur_ns: precise frame timing
> - * @framedur_ns: precise line timing
> + * @linedur_ns: precise line timing
>   * @pixeldur_ns: precise pixel timing
>   * @helper_private: mid-layer private data
>   * @properties: property tracking for this CRTC
> + * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
> + * 	legacy ioctls
>   *
>   * Each CRTC may have one or more connectors associated with it.  This structure
>   * allows the CRTC to be controlled.
> @@ -483,6 +489,7 @@ struct drm_encoder {
>   * @connector_type_id: index into connector type enum
>   * @interlace_allowed: can this connector handle interlaced modes?
>   * @doublescan_allowed: can this connector handle doublescan?
> + * @stereo_allowed: can this connector handle stereo modes?
>   * @modes: modes available on this connector (from fill_modes() + user)
>   * @status: one of the drm_connector_status enums (connected, not, or unknown)
>   * @probed_modes: list of modes derived directly from the display
> @@ -490,10 +497,13 @@ struct drm_encoder {
>   * @funcs: connector control functions
>   * @edid_blob_ptr: DRM property containing EDID if present
>   * @properties: property tracking for this connector
> + * @path_blob_ptr: DRM blob property data for the DP MST path property
>   * @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling
>   * @dpms: current dpms state
>   * @helper_private: mid-layer private data
> + * @cmdline_mode: mode line parsed from the kernel cmdline for this connector
>   * @force: a %DRM_FORCE_<foo> state for forced mode sets
> + * @override_edid: has the EDID been overwritten through debugfs for testing?
>   * @encoder_ids: valid encoders for this connector
>   * @encoder: encoder driving this connector, if any
>   * @eld: EDID-like data, if present
> @@ -503,6 +513,8 @@ struct drm_encoder {
>   * @video_latency: video latency info from ELD, if found
>   * @audio_latency: audio latency info from ELD, if found
>   * @null_edid_counter: track sinks that give us all zeros for the EDID
> + * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
> + * @debugfs_entry: debugfs directory for this connector
>   *
>   * Each connector may be connected to one or more CRTCs, or may be clonable by
>   * another connector if they can share a CRTC.  Each connector also has a specific
> @@ -570,6 +582,7 @@ struct drm_connector {
>   * @update_plane: update the plane configuration
>   * @disable_plane: shut down the plane
>   * @destroy: clean up plane resources
> + * @reset: reset plane after state has been invalidated (e.g. resume)
>   * @set_property: called when a property is changed
>   */
>  struct drm_plane_funcs {
> @@ -603,6 +616,8 @@ enum drm_plane_type {
>   * @format_count: number of formats supported
>   * @crtc: currently bound CRTC
>   * @fb: currently bound fb
> + * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
> + * 	drm_mode_set_config_internal() to implement correct refcounting.
>   * @funcs: helper functions
>   * @properties: property tracking for this plane
>   * @type: type of plane (overlay, primary, cursor)
> @@ -620,8 +635,6 @@ struct drm_plane {
>  	struct drm_crtc *crtc;
>  	struct drm_framebuffer *fb;
>  
> -	/* Temporary tracking of the old fb while a modeset is ongoing. Used
> -	 * by drm_mode_set_config_internal to implement correct refcounting. */
>  	struct drm_framebuffer *old_fb;
>  
>  	const struct drm_plane_funcs *funcs;
> @@ -680,7 +693,6 @@ struct drm_bridge {
>  
>  /**
>   * struct drm_mode_set - new values for a CRTC config change
> - * @head: list management
>   * @fb: framebuffer to use for new config
>   * @crtc: CRTC whose configuration we're about to change
>   * @mode: mode timings to use
> @@ -722,10 +734,11 @@ struct drm_mode_config_funcs {
>  };
>  
>  /**
> - * drm_mode_group - group of mode setting resources for potential sub-grouping
> + * struct drm_mode_group - group of mode setting resources for potential sub-grouping
>   * @num_crtcs: CRTC count
>   * @num_encoders: encoder count
>   * @num_connectors: connector count
> + * @num_bridges: bridge count
>   * @id_list: list of KMS object IDs in this group
>   *
>   * Currently this simply tracks the global mode setting state.  But in the
> @@ -745,10 +758,14 @@ struct drm_mode_group {
>  };
>  
>  /**
> - * drm_mode_config - Mode configuration control structure
> + * struct drm_mode_config - Mode configuration control structure
>   * @mutex: mutex protecting KMS related lists and structures
> + * @connection_mutex: ww mutex protecting connector state and routing
> + * @acquire_ctx: global implicit acquire context used by atomic drivers for
> + * 	legacy ioctls
>   * @idr_mutex: mutex for KMS ID allocation and management
>   * @crtc_idr: main KMS ID tracking object
> + * @fb_lock: mutex to protect fb state and lists
>   * @num_fb: number of fbs available
>   * @fb_list: list of framebuffers available
>   * @num_connector: number of connectors on this device
> @@ -757,17 +774,28 @@ struct drm_mode_group {
>   * @bridge_list: list of bridge objects
>   * @num_encoder: number of encoders on this device
>   * @encoder_list: list of encoder objects
> + * @num_overlay_plane: number of overlay planes on this device
> + * @num_total_plane: number of universal (i.e. with primary/curso) planes on this device
> + * @plane_list: list of plane objects
>   * @num_crtc: number of CRTCs on this device
>   * @crtc_list: list of CRTC objects
> + * @property_list: list of property objects
>   * @min_width: minimum pixel width on this device
>   * @min_height: minimum pixel height on this device
>   * @max_width: maximum pixel width on this device
>   * @max_height: maximum pixel height on this device
>   * @funcs: core driver provided mode setting functions
>   * @fb_base: base address of the framebuffer
> - * @poll_enabled: track polling status for this device
> + * @poll_enabled: track polling support for this device
> + * @poll_running: track polling status for this device
>   * @output_poll_work: delayed work for polling in process context
> + * @property_blob_list: list of all the blob property objects
>   * @*_property: core property tracking
> + * @preferred_depth: preferred RBG pixel depth, used by fb helpers
> + * @prefer_shadow: hint to userspace to prefer shadow-fb rendering
> + * @async_page_flip: does this device support async flips on the primary plane?
> + * @cursor_width: hint to userspace for max cursor width
> + * @cursor_height: hint to userspace for max cursor height
>   *
>   * Core mode resource tracking structure.  All CRTC, encoders, and connectors
>   * enumerated by the driver are added here, as are global properties.  Some
> @@ -781,14 +809,7 @@ struct drm_mode_config {
>  	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
>  	/* this is limited to one for now */
>  
> -
> -	/**
> -	 * fb_lock - mutex to protect fb state
> -	 *
> -	 * Besides the global fb list his also protects the fbs list in the
> -	 * file_priv
> -	 */
> -	struct mutex fb_lock;
> +	struct mutex fb_lock; /* proctects global and per-file fb lists */
>  	int num_fb;
>  	struct list_head fb_list;
>  
> -- 
> 2.1.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm: Pull drm_crtc.h into the kerneldoc template
  2014-11-02 19:18   ` [PATCH] " Daniel Vetter
@ 2014-11-03  3:04     ` Thierry Reding
  0 siblings, 0 replies; 77+ messages in thread
From: Thierry Reding @ 2014-11-03  3:04 UTC (permalink / raw)
  To: Daniel Vetter, DRI Development; +Cc: Intel Graphics Development

On November 2, 2014 8:18:15 PM Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> While writing atomic docs I've noticed that I don't get any errors
> for my screw-ups in drm_crtc.h. Fix this immediately.
>
> This just does the bare minimum to get starts, lots of stuff isn't
> properly documented yet unfortunately.
>
> v2: Fix adjacent spelling error Sean noticed.
>
> Reviewed-by: Sean Paul <seanpaul@chromium.org>
> Cc: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  Documentation/DocBook/drm.tmpl |  4 ++++
>  include/drm/drm_crtc.h         | 28 ++++++++++++++--------------
>  2 files changed, 18 insertions(+), 14 deletions(-)

Reviewed-by: Thierry Reding <treding@nvidia.com>


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
@ 2014-11-03 14:45   ` Daniel Thompson
  2014-11-03 14:53     ` Daniel Vetter
  2014-11-06 17:43   ` Sean Paul
  2014-11-06 19:55   ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Daniel Thompson @ 2014-11-03 14:45 UTC (permalink / raw)
  To: Daniel Vetter, DRI Development; +Cc: Intel Graphics Development

On 02/11/14 13:19, Daniel Vetter wrote:> The atomic users and helpers
assume that there is always a obj->state
> structure around. Which means drivers need to somehow create that at
> driver load time. Also it should obviously reset hardware state, so
> needs to be reset upon resume.
>
> Finally the destroy/duplicate_state functions are an awful lot of
> boilerplate if the driver doesn't need anything beyond the default
> state objects.
>
> So add helper functions for all of this.
>
> v2: Somehow the plane/connector versions got lost in the first
> version.
>
> v3: Add kerneldoc.
>
> v4: Make duplicate_state functions a bit more robust, which is useful
> for debugging state tracking issues when transitioning to atomic.
>
> v5: Clear temporary variables in the crtc state when duplicating it,
> like ->mode_changed or ->planes_changed. If we don't do this stale
> values for these might pollute the next atomic modeset.
>
> v6: Also clear crtc_state->event in case the driver didn't (yet) clear
> this out.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 154
+++++++++++++++++++++++++++++++++++-
>  include/drm/drm_atomic_helper.h     |  19 +++++
>  2 files changed, 170 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c
b/drivers/gpu/drm/drm_atomic_helper.c
> index 70bd67cf86e3..bd38df3cbe55 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1429,7 +1429,7 @@ EXPORT_SYMBOL(drm_atomic_helper_set_config);
>  /**
>   * drm_atomic_helper_crtc_set_property - helper for crtc prorties
>   * @crtc: DRM crtc
> - * @prorty: DRM property
> + * @property: DRM property

This looks like a bad fixup (should be in patch 11).


>   * @val: value of property
>   *
>   * Provides a default plane disablle handler using the atomic driver
interface.
> @@ -1493,7 +1493,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
>  /**
>   * drm_atomic_helper_plane_set_property - helper for plane prorties
>   * @plane: DRM plane
> - * @prorty: DRM property
> + * @property: DRM property

+1


>   * @val: value of property
>   *
>   * Provides a default plane disable handler using the atomic driver
interface.
> @@ -1557,7 +1557,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
>  /**
>   * drm_atomic_helper_connector_set_property - helper for connector
prorties
>   * @connector: DRM connector
> - * @prorty: DRM property
> + * @property: DRM property

+1


>   * @val: value of property
>   *
>   * Provides a default plane disablle handler using the atomic driver
interface.
> @@ -1707,3 +1707,151 @@ backoff:
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_page_flip);
> +
> +/**
> + * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
> + * @crtc: drm CRTC
> + *
> + * Resets the atomic state for @crtc by freeing the state pointer and
allocating
> + * a new empty state object.
> + */
> +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
> +{
> +	kfree(crtc->state);
> +	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);

This code looks semantically equivalent to a memset() although it may
result in a change to the pointer value. Is this code trying to flush
out uses-after-free?

I can't find this free/alloc pattern in delivered code anywhere else in
the drm code base. Should this need to be replaced with memset() before
merging (or at least commenting)?


> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
> +
> +/**
> + * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
> + * @crtc: drm CRTC
> + *
> + * Default CRTC state duplicate hook for drivers which don't have
their own
> + * subclassed CRTC state structure.
> + */
> +struct drm_crtc_state *
> +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
> +{
> +	struct drm_crtc_state *state;
> +
> +	if (WARN_ON(!crtc->state))
> +		return NULL;
> +
> +	state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
> +
> +	if (state) {
> +		state->mode_changed = false;
> +		state->planes_changed = false;
> +		state->event = NULL;
> +	}
> +
> +	return state;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_crtc_destroy_state - default state destroy hook
> + * @crtc: drm CRTC
> + * @state: CRTC state object to release
> + *
> + * Default CRTC state destroy hook for drivers which don't have their own
> + * subclassed CRTC state structure.
> + */
> +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
> +					  struct drm_crtc_state *state)
> +{
> +	kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
> +
> +/**
> + * drm_atomic_helper_plane_reset - default ->reset hook for planes
> + * @plane: drm plane
> + *
> + * Resets the atomic state for @plane by freeing the state pointer and
> + * allocating a new empty state object.
> + */
> +void drm_atomic_helper_plane_reset(struct drm_plane *plane)
> +{
> +	kfree(plane->state);
> +	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);

+1


> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
> +
> +/**
> + * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
> + * @plane: drm plane
> + *
> + * Default plane state duplicate hook for drivers which don't have
their own
> + * subclassed plane state structure.
> + */
> +struct drm_plane_state *
> +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
> +{
> +	if (WARN_ON(!plane->state))
> +		return NULL;
> +
> +	return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_plane_destroy_state - default state destroy hook
> + * @plane: drm plane
> + * @state: plane state object to release
> + *
> + * Default plane state destroy hook for drivers which don't have
their own
> + * subclassed plane state structure.
> + */
> +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
> +					  struct drm_plane_state *state)
> +{
> +	kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
> +
> +/**
> + * drm_atomic_helper_connector_reset - default ->reset hook for
connectors
> + * @connector: drm connector
> + *
> + * Resets the atomic state for @connector by freeing the state
pointer and
> + * allocating a new empty state object.
> + */
> +void drm_atomic_helper_connector_reset(struct drm_connector *connector)
> +{
> +	kfree(connector->state);
> +	connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);

+1


> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
> +
> +/**
> + * drm_atomic_helper_connector_duplicate_state - default state
duplicate hook
> + * @connector: drm connector
> + *
> + * Default connector state duplicate hook for drivers which don't
have their own
> + * subclassed connector state structure.
> + */
> +struct drm_connector_state *
> +drm_atomic_helper_connector_duplicate_state(struct drm_connector
*connector)
> +{
> +	if (WARN_ON(!connector->state))
> +		return NULL;
> +
> +	return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_connector_destroy_state - default state destroy hook
> + * @connector: drm connector
> + * @state: connector state object to release
> + *
> + * Default connector state destroy hook for drivers which don't have
their own
> + * subclassed connector state structure.
> + */
> +void drm_atomic_helper_connector_destroy_state(struct drm_connector
*connector,
> +					  struct drm_connector_state *state)
> +{
> +	kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
> diff --git a/include/drm/drm_atomic_helper.h
b/include/drm/drm_atomic_helper.h
> index 28a2f3a815fd..67e3c4645ae0 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -74,5 +74,24 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
>  				struct drm_pending_vblank_event *event,
>  				uint32_t flags);
>
> +/* default implementations for state handling */
> +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
> +struct drm_crtc_state *
> +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
> +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
> +					  struct drm_crtc_state *state);
> +
> +void drm_atomic_helper_plane_reset(struct drm_plane *plane);
> +struct drm_plane_state *
> +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
> +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
> +					  struct drm_plane_state *state);
> +
> +void drm_atomic_helper_connector_reset(struct drm_connector *connector);
> +struct drm_connector_state *
> +drm_atomic_helper_connector_duplicate_state(struct drm_connector
*connector);
> +void drm_atomic_helper_connector_destroy_state(struct drm_connector
*connector,
> +					  struct drm_connector_state *state);
> +
>
>  #endif /* DRM_ATOMIC_HELPER_H_ */
>


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

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-03 14:45   ` Daniel Thompson
@ 2014-11-03 14:53     ` Daniel Vetter
  2014-11-03 15:06       ` Daniel Thompson
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-03 14:53 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Mon, Nov 03, 2014 at 02:45:28PM +0000, Daniel Thompson wrote:
> > index 70bd67cf86e3..bd38df3cbe55 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -1429,7 +1429,7 @@ EXPORT_SYMBOL(drm_atomic_helper_set_config);
> >  /**
> >   * drm_atomic_helper_crtc_set_property - helper for crtc prorties
> >   * @crtc: DRM crtc
> > - * @prorty: DRM property
> > + * @property: DRM property
> 
> This looks like a bad fixup (should be in patch 11).

Indeed, will shuffle around.

> > +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
> > +{
> > +	kfree(crtc->state);
> > +	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
> 
> This code looks semantically equivalent to a memset() although it may
> result in a change to the pointer value. Is this code trying to flush
> out uses-after-free?
> 
> I can't find this free/alloc pattern in delivered code anywhere else in
> the drm code base. Should this need to be replaced with memset() before
> merging (or at least commenting)?

kfree is a nop when the argument is NULL, which is a crucial property of
this - memset would oops on driver load.

Even neglecting this a memset imo doesn't blow up loudly enough if the
driver subclasses the state structs (by adding more of it's driver private
state at the end). Whereas underallocating tends to anger the slab
poisoning code badly.

Finally it's really not just a memset, but a free + realloc. See the plane
state, which also needs to drop a potential fb reference. Imo the explicit
kfree+realloc makes that more obvious.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-03 14:53     ` Daniel Vetter
@ 2014-11-03 15:06       ` Daniel Thompson
  2014-11-03 15:11         ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Thompson @ 2014-11-03 15:06 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On 03/11/14 14:53, Daniel Vetter wrote:
> On Mon, Nov 03, 2014 at 02:45:28PM +0000, Daniel Thompson wrote:
>>> index 70bd67cf86e3..bd38df3cbe55 100644
>>> --- a/drivers/gpu/drm/drm_atomic_helper.c
>>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
>>> @@ -1429,7 +1429,7 @@ EXPORT_SYMBOL(drm_atomic_helper_set_config);
>>>  /**
>>>   * drm_atomic_helper_crtc_set_property - helper for crtc prorties
>>>   * @crtc: DRM crtc
>>> - * @prorty: DRM property
>>> + * @property: DRM property
>>
>> This looks like a bad fixup (should be in patch 11).
> 
> Indeed, will shuffle around.
> 
>>> +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
>>> +{
>>> +	kfree(crtc->state);
>>> +	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
>>
>> This code looks semantically equivalent to a memset() although it may
>> result in a change to the pointer value. Is this code trying to flush
>> out uses-after-free?
>>
>> I can't find this free/alloc pattern in delivered code anywhere else in
>> the drm code base. Should this need to be replaced with memset() before
>> merging (or at least commenting)?
> 
> kfree is a nop when the argument is NULL, which is a crucial property of
> this - memset would oops on driver load.

Oops. Missed that (I think I misread who as assuming there was always
obj->state in the patch header).

Do you fancy making the comment "by freeing the state pointer and
allocating a new..." into "by freeing the state pointer (which may be
NULL) and allocating a new...".

If nothing else that means the documentation is richer than the code...

> Even neglecting this a memset imo doesn't blow up loudly enough if the
> driver subclasses the state structs (by adding more of it's driver private
> state at the end). Whereas underallocating tends to anger the slab
> poisoning code badly.
> 
> Finally it's really not just a memset, but a free + realloc. See the plane
> state, which also needs to drop a potential fb reference. Imo the explicit
> kfree+realloc makes that more obvious.

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

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-03 15:06       ` Daniel Thompson
@ 2014-11-03 15:11         ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-03 15:11 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Mon, Nov 03, 2014 at 03:06:07PM +0000, Daniel Thompson wrote:
> > kfree is a nop when the argument is NULL, which is a crucial property of
> > this - memset would oops on driver load.
> 
> Oops. Missed that (I think I misread who as assuming there was always
> obj->state in the patch header).
> 
> Do you fancy making the comment "by freeing the state pointer and
> allocating a new..." into "by freeing the state pointer (which may be
> NULL) and allocating a new...".
> 
> If nothing else that means the documentation is richer than the code...

Yeah, sounds like a good idea. I'll also mention that this is for driver
load mostly (if the driver doesn't decide to throw away the state for some
reason over suspend/resume).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 06/17] drm: Global atomic state handling
  2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
@ 2014-11-03 23:41   ` Matt Roper
  2014-11-04  8:40     ` Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
  2014-11-04 21:37   ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Matt Roper @ 2014-11-03 23:41 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Fengguang Wu, DRI Development

On Sun, Nov 02, 2014 at 02:19:19PM +0100, Daniel Vetter wrote:
...
> +/**
> + * drm_atomic_get_plane_state - get plane state
> + * @state: global atomic state object
> + * @plane: plane to get state object for
> + *
> + * This functions returns the plane state for the given plane, allocating it if
> + * needed. It will also grab the relevant plane lock to make sure that the state
> + * is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +			  struct drm_plane *plane)
> +{
> +	int ret, index;
> +	struct drm_plane_state *plane_state;
> +
> +	index = drm_plane_index(plane);
> +
> +	if (state->plane_states[index])
> +		return state->plane_states[index];
> +
> +	/*
> +	 * TODO: We currently don't have per-plane mutexes. So instead of trying
> +	 * crazy tricks with deferring plane->crtc and hoping for the best just
> +	 * grab all crtc locks. Once we have per-plane locks we must update this
> +	 * to only take the plane mutex.
> +	 */
> +	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	plane_state = plane->funcs->atomic_duplicate_state(plane);
> +	if (!plane_state)
> +		return ERR_PTR(-ENOMEM);
> +
> +	state->plane_states[index] = plane_state;
> +	state->planes[index] = plane;
> +	plane_state->state = state;
> +
> +	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> +		      plane->base.id, plane_state, state);
> +
> +	if (plane_state->crtc) {
> +		struct drm_crtc_state *crtc_state;
> +
> +		crtc_state = drm_atomic_get_crtc_state(state,
> +						       plane_state->crtc);
> +		if (IS_ERR(crtc_state))
> +			return ERR_CAST(crtc_state);
> +	}

It's not immediately clear to me why we need to get (create) the crtc
state here.  Is this just so that we know to do an
atomic_begin()/atomic_flush() on this crtc later or do we actually use
the state itself somewhere that I'm overlooking?


Matt

-- 
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 06/17] drm: Global atomic state handling
  2014-11-03 23:41   ` Matt Roper
@ 2014-11-04  8:40     ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04  8:40 UTC (permalink / raw)
  To: Matt Roper
  Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu, DRI Development

On Mon, Nov 03, 2014 at 03:41:32PM -0800, Matt Roper wrote:
> On Sun, Nov 02, 2014 at 02:19:19PM +0100, Daniel Vetter wrote:
> ...
> > +/**
> > + * drm_atomic_get_plane_state - get plane state
> > + * @state: global atomic state object
> > + * @plane: plane to get state object for
> > + *
> > + * This functions returns the plane state for the given plane, allocating it if
> > + * needed. It will also grab the relevant plane lock to make sure that the state
> > + * is consistent.
> > + *
> > + * Returns:
> > + *
> > + * Either the allocated state or the error code encoded into the pointer. When
> > + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> > + * entire atomic sequence must be restarted. All other errors are fatal.
> > + */
> > +struct drm_plane_state *
> > +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> > +			  struct drm_plane *plane)
> > +{
> > +	int ret, index;
> > +	struct drm_plane_state *plane_state;
> > +
> > +	index = drm_plane_index(plane);
> > +
> > +	if (state->plane_states[index])
> > +		return state->plane_states[index];
> > +
> > +	/*
> > +	 * TODO: We currently don't have per-plane mutexes. So instead of trying
> > +	 * crazy tricks with deferring plane->crtc and hoping for the best just
> > +	 * grab all crtc locks. Once we have per-plane locks we must update this
> > +	 * to only take the plane mutex.
> > +	 */
> > +	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
> > +	if (ret)
> > +		return ERR_PTR(ret);
> > +
> > +	plane_state = plane->funcs->atomic_duplicate_state(plane);
> > +	if (!plane_state)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	state->plane_states[index] = plane_state;
> > +	state->planes[index] = plane;
> > +	plane_state->state = state;
> > +
> > +	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> > +		      plane->base.id, plane_state, state);
> > +
> > +	if (plane_state->crtc) {
> > +		struct drm_crtc_state *crtc_state;
> > +
> > +		crtc_state = drm_atomic_get_crtc_state(state,
> > +						       plane_state->crtc);
> > +		if (IS_ERR(crtc_state))
> > +			return ERR_CAST(crtc_state);
> > +	}
> 
> It's not immediately clear to me why we need to get (create) the crtc
> state here.  Is this just so that we know to do an
> atomic_begin()/atomic_flush() on this crtc later or do we actually use
> the state itself somewhere that I'm overlooking?

I do the same when grabbing the connector state and also add the crtc to
the lookup table. The reasoning is that essentially I couldn't come up
with any sane driver implementation where you would not want to have the
CRTC state (maybe just for a bit of book-keeping) if you either have a
plane or a connector using it. And then grabbing the state will also grab
the locks, which is fairly convenient.

Note that the core functions to change the links will grab the state+lock
of the new target for you, too.

Now what I didn't do is grab _all_ the connectors/planes for a given crtc
as soon as you grab the crtcs state. Especially for plane updates I think
most drivers don't need that, and even if you do a mode change you might
be able to implement that without touching the connectors at all. E.g. on
i915 we can change the pfit to change the "mode" on panels.

But there are helpers to grab all affected connectors since that's needed
by the new atomic modeset helpers. This stuff here is core, and I've put
it here since I really couldn't make up a sane driver that wouldn't need
this.
-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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 06/17] drm: Global atomic state handling
  2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
  2014-11-03 23:41   ` Matt Roper
@ 2014-11-04 20:31   ` Sean Paul
  2014-11-04 21:30     ` Daniel Vetter
  2014-11-04 21:37   ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-04 20:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Fengguang Wu, DRI Development

On Sun, Nov 02, 2014 at 02:19:19PM +0100, Daniel Vetter wrote:
> Some differences compared to Rob's patches again:
> - Dropped the committed and checked booleans. Checking will be
>   internally enforced by always calling ->atomic_check before
>   ->atomic_commit. And async handling needs to be solved differently
>   because the current scheme completely side-steps ww mutex deadlock
>   avoidance (and so either reinvents a new deadlock avoidance wheel or
>   like the current code just deadlocks).
>
> - State for connectors needed to be added, since now they have a
>   full-blown drm_connector_state (so that drivers have something to
>   attach their own stuff to).
>
> - Refcounting is gone. I plane to solve async updates differently,
>   since the lock-passing scheme doesn't cut it (since it abuses ww
>   mutexes). Essentially what we need for async is a simple ownership
>   transfer from the caller to the driver. That doesn't need full-blown
>   refcounting.
>
> - The acquire ctx is a pointer. Real atomic callers should have that
>   on their stack, legacy entry points need to put the right one
>   (obtained by drm_modeset_legacy_acuire_ctx) in there.
>
> - I've dropped all hooks except check/commit. All the begin/end
>   handling is done by core functions and is the same.
>
> - commit/check are just thin wrappers that ensure that ->check is
>   always called.
>
> - To help out with locking in the legacy implementations I've added a
>   helper to just grab all locks in the backoff case.
>
> v2: Add notices that check/commit can fail with EDEADLK.
>
> v3:
> - More consistent naming for state_alloc.
> - Add state_clear which is needed for backoff and retry.
>
> v4: Planes/connectors can switch between crtcs, and we need to be
> careful that we grab the state (and locks) for both the old and new
> crtc. Improve the interface functions to ensure this.
>
> v5: Add functions to grab affected connectors for a crtc and to recompute
> the crtc->enable state. This is useful for both helper and atomic ioctl
> code when e.g. removing a connector.
>
> v6: Squash in fixup from Fengguang to use ERR_CAST.
>
> v7: Add debug output.
>
> v8: Make checkpatch happy about kcalloc argument ordering.
>
> v9: Improve kerneldoc in drm_crtc.h
>
> v10:
> - Fix another kcalloc argument misorder I've missed.
> - More polish for kerneldoc.
>
> v11: Clarify the ownership rules for the state object. The new rule is
> that a successful drm_atomic_commit (whether synchronous or asnyc)
> always inherits the state and is responsible for the clean-up. That
> way async and sync ->commit functions are more similar.
>
> v12: A few bugfixes:
> - Assign state->state pointers correctly when grabbing state objects -
>   we need to link them up with the global state.
> - Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
>   for the callers of this function.
>
> Cc: Fengguang Wu <fengguang.wu@intel.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/Makefile     |   2 +-
>  drivers/gpu/drm/drm_atomic.c | 588 +++++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic.h     |  63 +++++
>  include/drm/drm_crtc.h       |  35 +++
>  4 files changed, 687 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_atomic.c
>  create mode 100644 include/drm/drm_atomic.h
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index a3149e20a249..2e89cd50c14f 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -14,7 +14,7 @@ drm-y       := drm_auth.o drm_bufs.o drm_cache.o \
>   drm_info.o drm_debugfs.o drm_encoder_slave.o \
>   drm_trace_points.o drm_global.o drm_prime.o \
>   drm_rect.o drm_vma_manager.o drm_flip_work.o \
> - drm_modeset_lock.o
> + drm_modeset_lock.o drm_atomic.o
>
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> new file mode 100644
> index 000000000000..c6db8a48cad6
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -0,0 +1,588 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_plane_helper.h>
> +
> +static void kfree_state(struct drm_atomic_state *state)
> +{
> + kfree(state->connectors);
> + kfree(state->connector_states);
> + kfree(state->crtcs);
> + kfree(state->crtc_states);
> + kfree(state->planes);
> + kfree(state->plane_states);
> + kfree(state);
> +}
> +
> +/**
> + * drm_atomic_state_alloc - allocate atomic state
> + * @dev: DRM device
> + *
> + * This allocates an empty atomic state to track updates.
> + */
> +struct drm_atomic_state *
> +drm_atomic_state_alloc(struct drm_device *dev)
> +{
> + struct drm_atomic_state *state;
> +
> + state = kzalloc(sizeof(*state), GFP_KERNEL);
> + if (!state)
> + return NULL;
> +
> + state->crtcs = kcalloc(dev->mode_config.num_crtc,
> +       sizeof(*state->crtcs), GFP_KERNEL);
> + if (!state->crtcs)
> + goto fail;
> + state->crtc_states = kcalloc(dev->mode_config.num_crtc,
> +     sizeof(*state->crtc_states), GFP_KERNEL);
> + if (!state->crtc_states)
> + goto fail;
> + state->planes = kcalloc(dev->mode_config.num_total_plane,
> + sizeof(*state->plane_states), GFP_KERNEL);

sizeof(*state->planes)

> + if (!state->planes)
> + goto fail;
> + state->plane_states = kcalloc(dev->mode_config.num_total_plane,
> +      sizeof(*state->plane_states), GFP_KERNEL);
> + if (!state->plane_states)
> + goto fail;
> + state->connectors = kcalloc(dev->mode_config.num_connector,
> +    sizeof(*state->connectors),
> +    GFP_KERNEL);
> + if (!state->connectors)
> + goto fail;
> + state->connector_states = kcalloc(dev->mode_config.num_connector,
> +  sizeof(*state->connector_states),
> +  GFP_KERNEL);
> + if (!state->connector_states)
> + goto fail;
> +
> + state->dev = dev;
> +
> + DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
> +
> + return state;
> +fail:
> + kfree_state(state);
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL(drm_atomic_state_alloc);
> +
> +/**
> + * drm_atomic_state_clear - clear state object
> + * @state: atomic state
> + *
> + * When the w/w mutex algorithm detects a deadlock we need to back off and drop
> + * all locks. So someone else could sneak in and change the current modeset
> + * configuration. Which means that all the state assembled in @state is no
> + * longer an atomic update to the current state, but to some arbitrary earlier
> + * state. Which could break assumptions the driver's ->atomic_check likely
> + * relies on.
> + *
> + * Hence we must clear all cached state and completely start over, using this
> + * function.
> + */
> +void drm_atomic_state_clear(struct drm_atomic_state *state)
> +{
> + struct drm_device *dev = state->dev;
> + int i;
> +
> + DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
> +
> + for (i = 0; i < dev->mode_config.num_connector; i++) {
> + struct drm_connector *connector = state->connectors[i];
> +
> + if (!connector)
> + continue;
> +
> + connector->funcs->atomic_destroy_state(connector,
> +       state->connector_states[i]);
> + }
> +
> + for (i = 0; i < dev->mode_config.num_crtc; i++) {
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + crtc->funcs->atomic_destroy_state(crtc,
> +  state->crtc_states[i]);
> + }
> +
> + for (i = 0; i < dev->mode_config.num_total_plane; i++) {
> + struct drm_plane *plane = state->planes[i];
> +
> + if (!plane)
> + continue;
> +
> + plane->funcs->atomic_destroy_state(plane,
> +   state->plane_states[i]);
> + }
> +}
> +EXPORT_SYMBOL(drm_atomic_state_clear);
> +
> +/**
> + * drm_atomic_state_free - free all memory for an atomic state
> + * @state: atomic state to deallocate
> + *
> + * This frees all memory associated with an atomic state, including all the
> + * per-object state for planes, crtcs and connectors.
> + */
> +void drm_atomic_state_free(struct drm_atomic_state *state)
> +{
> + drm_atomic_state_clear(state);
> +
> + DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
> +
> + kfree_state(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_state_free);
> +
> +/**
> + * drm_atomic_get_crtc_state - get crtc state
> + * @state: global atomic state object
> + * @crtc: crtc to get state object for
> + *
> + * This functions returns the crtc state for the given crtc, allocating it if

nit: s/functions/function

Looks like this happens a few times throughout the file

> + * needed. It will also grab the relevant crtc lock to make sure that the state
> + * is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_crtc_state *
> +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> +  struct drm_crtc *crtc)
> +{
> + int ret, index;
> + struct drm_crtc_state *crtc_state;
> +
> + index = drm_crtc_index(crtc);
> +
> + if (state->crtc_states[index])
> + return state->crtc_states[index];
> +
> + ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
> + if (!crtc_state)
> + return ERR_PTR(-ENOMEM);
> +
> + state->crtc_states[index] = crtc_state;
> + state->crtcs[index] = crtc;
> + crtc_state->state = state;
> +
> + DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
> +      crtc->base.id, crtc_state, state);
> +
> + return crtc_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_crtc_state);
> +
> +/**
> + * drm_atomic_get_plane_state - get plane state
> + * @state: global atomic state object
> + * @plane: plane to get state object for
> + *
> + * This functions returns the plane state for the given plane, allocating it if
> + * needed. It will also grab the relevant plane lock to make sure that the state
> + * is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +  struct drm_plane *plane)
> +{
> + int ret, index;
> + struct drm_plane_state *plane_state;
> +
> + index = drm_plane_index(plane);
> +
> + if (state->plane_states[index])
> + return state->plane_states[index];
> +
> + /*
> + * TODO: We currently don't have per-plane mutexes. So instead of trying
> + * crazy tricks with deferring plane->crtc and hoping for the best just
> + * grab all crtc locks. Once we have per-plane locks we must update this
> + * to only take the plane mutex.
> + */
> + ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + plane_state = plane->funcs->atomic_duplicate_state(plane);
> + if (!plane_state)
> + return ERR_PTR(-ENOMEM);
> +
> + state->plane_states[index] = plane_state;
> + state->planes[index] = plane;
> + plane_state->state = state;
> +
> + DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> +      plane->base.id, plane_state, state);
> +
> + if (plane_state->crtc) {
> + struct drm_crtc_state *crtc_state;
> +
> + crtc_state = drm_atomic_get_crtc_state(state,
> +       plane_state->crtc);
> + if (IS_ERR(crtc_state))
> + return ERR_CAST(crtc_state);
> + }
> +
> + return plane_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_plane_state);
> +
> +/**
> + * drm_atomic_get_connector_state - get connector state
> + * @state: global atomic state object
> + * @connector: connector to get state object for
> + *
> + * This functions returns the connector state for the given connector,
> + * allocating it if needed. It will also grab the relevant connector lock to
> + * make sure that the state is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_connector_state *
> +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> +  struct drm_connector *connector)
> +{
> + int ret, index;
> + struct drm_mode_config *config = &connector->dev->mode_config;
> + struct drm_connector_state *connector_state;
> +
> + index = drm_connector_index(connector);
> +
> + if (state->connector_states[index])
> + return state->connector_states[index];
> +
> + ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + connector_state = connector->funcs->atomic_duplicate_state(connector);
> + if (!connector_state)
> + return ERR_PTR(-ENOMEM);
> +
> + state->connector_states[index] = connector_state;
> + state->connectors[index] = connector;
> + connector_state->state = state;
> +
> + DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
> +      connector->base.id, connector_state, state);
> +
> + if (connector_state->crtc) {
> + struct drm_crtc_state *crtc_state;
> +
> + crtc_state = drm_atomic_get_crtc_state(state,
> +       connector_state->crtc);
> + if (IS_ERR(crtc_state))
> + return ERR_CAST(crtc_state);
> + }
> +
> + return connector_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_connector_state);
> +
> +/**
> + * drm_atomic_set_crtc_for_plane - set crtc for plane
> + * @plane_state: atomic state object for the plane
> + * @crtc: crtc to use for the plane
> + *
> + * Changing the assigned crtc for a plane requires us to grab the lock and state
> + * for the new crtc, as needed. This function takes care of all these details
> + * besides updating the pointer in the state object itself.
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
> +      struct drm_crtc *crtc)
> +{
> + struct drm_crtc_state *crtc_state;
> +
> + if (crtc) {
> + crtc_state = drm_atomic_get_crtc_state(plane_state->state,
> +       crtc);
> + if (IS_ERR(crtc_state))
> + return PTR_ERR(crtc_state);
> + }
> +
> + plane_state->crtc = crtc;
> +
> + if (crtc)
> + DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
> +      plane_state, crtc->base.id);
> + else
> + DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
> +
> +/**
> + * drm_atomic_set_crtc_for_connector - set crtc for connector
> + * @conn_state: atomic state object for the connector
> + * @crtc: crtc to use for the connector
> + *
> + * Changing the assigned crtc for a connector requires us to grab the lock and
> + * state for the new crtc, as needed. This function takes care of all these
> + * details besides updating the pointer in the state object itself.
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> +  struct drm_crtc *crtc)
> +{
> + struct drm_crtc_state *crtc_state;
> +
> + crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
> + if (IS_ERR(crtc_state))
> + return PTR_ERR(crtc_state);
> +
> + conn_state->crtc = crtc;
> +
> + DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
> +      conn_state, crtc->base.id);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);

In drm_atomic_helper.c, you're assigning directly to conn_state->crtc. I think
you should probably be using this helper (as it doesn't seem to be used
anywhere). I realize this happens in a different patch, but I want to make sure
I don't miss it later :-)

If that is the case, I think this could also benefit from the !crtc checks the
plane equivalent has.

> +
> +/**
> + * drm_atomic_add_affected_connectors - add connectors for crtc
> + * @state: atomic state
> + * @crtc: DRM crtc
> + *
> + * This functions walks the current configuration and adds all connectors
> + * currently using @crtc to the atomic configuration @state. Note that this
> + * function must acquire the connection mutex. This can potentially cause
> + * unneeded seralization if the update is just for the planes on one crtc. Hence
> + * drivers and helpers should only call this when really needed (e.g. when a
> + * full modeset needs to happen due to some change).
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> +   struct drm_crtc *crtc)
> +{
> + struct drm_mode_config *config = &state->dev->mode_config;
> + struct drm_connector *connector;
> + struct drm_connector_state *conn_state;
> + int ret;
> +
> + ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
> + if (ret)
> + return ret;
> +
> + DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
> +      crtc->base.id, state);
> +
> + /*
> + * Changed connectors are already in @state, so only need to look at the
> + * current configuration.
> + */
> + list_for_each_entry(connector, &config->connector_list, head) {
> + if (connector->state->crtc != crtc)
> + continue;
> +
> + conn_state = drm_atomic_get_connector_state(state, connector);
> + if (IS_ERR(conn_state))
> + return PTR_ERR(conn_state);
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
> +
> +/**
> + * drm_atomic_connectors_for_crtc - count number of connected outputs
> + * @state: atomic state
> + * @crtc: DRM crtc
> + *
> + * This function counts all connectors which will be connected to @crtc
> + * according to @state. Useful to recompute the enable state for @crtc.
> + */
> +int
> +drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
> +       struct drm_crtc *crtc)
> +{
> + int nconnectors = state->dev->mode_config.num_connector;
> + int i, num_connected_connectors = 0;
> +
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector_state *conn_state;
> +
> + conn_state = state->connector_states[i];
> +
> + if (conn_state && conn_state->crtc == crtc)
> + num_connected_connectors++;
> + }
> +
> + DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
> +      state, num_connected_connectors, crtc->base.id);
> +
> + return num_connected_connectors;
> +}
> +EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
> +
> +/**
> + * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
> + * @state: atomic state
> + *
> + * This function should be used by legacy entry points which don't understand
> + * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
> + *  the slowpath completed.
> + */
> +void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
> +{
> + int ret;
> +
> +retry:
> + drm_modeset_backoff(state->acquire_ctx);
> +
> + ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
> +       state->acquire_ctx);
> + if (ret)
> + goto retry;
> + ret = drm_modeset_lock_all_crtcs(state->dev,
> + state->acquire_ctx);
> + if (ret)
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_legacy_backoff);
> +
> +/**
> + * drm_atomic_check_only - check whether a given config would work
> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_check_only(struct drm_atomic_state *state)
> +{
> + struct drm_mode_config *config = &state->dev->mode_config;
> +
> + DRM_DEBUG_KMS("checking %p\n", state);
> +
> + if (config->funcs->atomic_check)
> + return config->funcs->atomic_check(state->dev, state);
> + else
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_check_only);
> +
> +/**
> + * drm_atomic_commit - commit configuration atomically
> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Also note that on successful execution ownership of @state is transferred
> + * from the caller of this function to the function itself. The caller must not
> + * free or in any other way access @state. If the function fails then the caller
> + * must clean up @state itself.
> + *
> + * Returns:
> + * 0 on etuccess, negative error code on failure.

s/et/s/

> + */
> +int drm_atomic_commit(struct drm_atomic_state *state)
> +{
> + struct drm_mode_config *config = &state->dev->mode_config;
> + int ret;
> +
> + ret = drm_atomic_check_only(state);
> + if (ret)
> + return ret;
> +
> + DRM_DEBUG_KMS("commiting %p\n", state);
> +
> + return config->funcs->atomic_commit(state->dev, state, false);
> +}
> +EXPORT_SYMBOL(drm_atomic_commit);
> +
> +/**
> + * drm_atomic_async_commit - atomic&async onfiguration commit

s/onfiguration/configuration/

> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Also note that on successful execution ownership of @state is transferred
> + * from the caller of this function to the function itself. The caller must not
> + * free or in any other way access @state. If the function fails then the caller
> + * must clean up @state itself.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_async_commit(struct drm_atomic_state *state)
> +{
> + struct drm_mode_config *config = &state->dev->mode_config;
> + int ret;
> +
> + ret = drm_atomic_check_only(state);
> + if (ret)
> + return ret;
> +
> + DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
> +
> + return config->funcs->atomic_commit(state->dev, state, true);
> +}
> +EXPORT_SYMBOL(drm_atomic_async_commit);
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> new file mode 100644
> index 000000000000..753812034e71
> --- /dev/null
> +++ b/include/drm/drm_atomic.h
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +#ifndef DRM_ATOMIC_H_
> +#define DRM_ATOMIC_H_
> +
> +struct drm_atomic_state *
> +drm_atomic_state_alloc(struct drm_device *dev);
> +void drm_atomic_state_clear(struct drm_atomic_state *state);
> +void drm_atomic_state_free(struct drm_atomic_state *state);
> +
> +struct drm_crtc_state *
> +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> +  struct drm_crtc *crtc);
> +struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +   struct drm_plane *plane);
> +struct drm_connector_state *
> +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> +       struct drm_connector *connector);
> +
> +int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
> +  struct drm_crtc *crtc);
> +int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> +      struct drm_crtc *crtc);
> +int
> +drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> +   struct drm_crtc *crtc);
> +int
> +drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
> +       struct drm_crtc *crtc);
> +
> +void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
> +
> +int drm_atomic_check_only(struct drm_atomic_state *state);
> +int drm_atomic_commit(struct drm_atomic_state *state);
> +int drm_atomic_async_commit(struct drm_atomic_state *state);
> +
> +#endif /* DRM_ATOMIC_H_ */
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 9847009ad451..c3ce5b36da5f 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -799,6 +799,32 @@ struct drm_bridge {
>  };
>
>  /**
> + * struct struct drm_atomic_state - the global state object for atomic updates
> + * @dev: parent DRM device
> + * @flags: state flags like async update
> + * @planes: pointer to array of plane pointers
> + * @plane_states: pointer to array of plane states pointers
> + * @crtcs: pointer to array of CRTC pointers
> + * @crtc_states: pointer to array of CRTC states pointers
> + * @connectors: pointer to array of connector pointers
> + * @connector_states: pointer to array of connector states pointers
> + * @acquire_ctx: acquire context for this atomic modeset state update
> + */
> +struct drm_atomic_state {
> +       struct drm_device *dev;
> +       uint32_t flags;
> +       struct drm_plane **planes;
> +       struct drm_plane_state **plane_states;
> +       struct drm_crtc **crtcs;
> +       struct drm_crtc_state **crtc_states;
> +       struct drm_connector **connectors;
> +       struct drm_connector_state **connector_states;
> +
> +       struct drm_modeset_acquire_ctx *acquire_ctx;
> +};
> +
> +
> +/**
>   * struct drm_mode_set - new values for a CRTC config change
>   * @fb: framebuffer to use for new config
>   * @crtc: CRTC whose configuration we're about to change
> @@ -829,6 +855,9 @@ struct drm_mode_set {
>   * struct drm_mode_config_funcs - basic driver provided mode setting functions
>   * @fb_create: create a new framebuffer object
>   * @output_poll_changed: function to handle output configuration changes
> + * @atomic_check: check whether a give atomic state update is possible
> + * @atomic_commit: commit an atomic state update previously verified with
> + * atomic_check()
>   *
>   * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
>   * involve drivers.
> @@ -838,6 +867,12 @@ struct drm_mode_config_funcs {
>       struct drm_file *file_priv,
>       struct drm_mode_fb_cmd2 *mode_cmd);
>   void (*output_poll_changed)(struct drm_device *dev);
> +
> + int (*atomic_check)(struct drm_device *dev,
> +    struct drm_atomic_state *a);
> + int (*atomic_commit)(struct drm_device *dev,
> +     struct drm_atomic_state *a,
> +     bool async);
>  };
>
>  /**
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h
  2014-11-02 13:19 ` [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h Daniel Vetter
@ 2014-11-04 20:31   ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-04 20:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:14PM +0100, Daniel Vetter wrote:
> Just a bit of OCD cleanup on headers - this function isn't the core
> interface any more but just a helper for drivers who haven't yet
> transitioned to universal planes. Put the declaration at the right
> spot and sprinkle necessary #includes over all drivers.
>
> Maybe this helps to encourage driver maintainers to do the switch.
>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Reviewed-by: Matt Roper <matthew.d.roper@intel.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
>  drivers/gpu/drm/armada/armada_crtc.c       | 1 +
>  drivers/gpu/drm/ast/ast_mode.c             | 1 +
>  drivers/gpu/drm/bochs/bochs_kms.c          | 1 +
>  drivers/gpu/drm/cirrus/cirrus_mode.c       | 1 +
>  drivers/gpu/drm/gma500/psb_intel_display.c | 1 +
>  drivers/gpu/drm/mgag200/mgag200_mode.c     | 1 +
>  drivers/gpu/drm/nouveau/dispnv04/crtc.c    | 1 +
>  drivers/gpu/drm/nouveau/nv50_display.c     | 1 +
>  drivers/gpu/drm/omapdrm/omap_crtc.c        | 1 +
>  drivers/gpu/drm/qxl/qxl_display.c          | 1 +
>  drivers/gpu/drm/radeon/radeon_display.c    | 1 +
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c     | 1 +
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c  | 1 +
>  drivers/gpu/drm/sti/sti_drm_crtc.c         | 1 +
>  drivers/gpu/drm/tegra/dc.c                 | 1 +
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c       | 1 +
>  drivers/gpu/drm/udl/udl_modeset.c          | 1 +
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c        | 1 +
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c       | 1 +
>  drivers/staging/imx-drm/imx-drm-core.c     | 1 +
>  include/drm/drm_crtc.h                     | 3 ---
>  include/drm/drm_plane_helper.h             | 4 ++++
>  22 files changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index 9a0cc09e6653..0b164fb1c107 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -12,6 +12,7 @@
>  #include <linux/platform_device.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include "armada_crtc.h"
>  #include "armada_drm.h"
>  #include "armada_fb.h"
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index 19ada0bbe319..df986498d376 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -31,6 +31,7 @@
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include "ast_drv.h"
>
>  #include "ast_tables.h"
> diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> index 6b7efcf363d6..5ffd4895d040 100644
> --- a/drivers/gpu/drm/bochs/bochs_kms.c
> +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> @@ -6,6 +6,7 @@
>   */
>
>  #include "bochs.h"
> +#include <drm/drm_plane_helper.h>
>
>  static int defx = 1024;
>  static int defy = 768;
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> index c7c5a9d91fa0..99d4a74ffeaf 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> @@ -16,6 +16,7 @@
>   */
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include <video/cirrus.h>
>
> diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> index 87b50ba64ed4..b21a09451d1d 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> @@ -21,6 +21,7 @@
>  #include <linux/i2c.h>
>
>  #include <drm/drmP.h>
> +#include <drm/drm_plane_helper.h>
>  #include "framebuffer.h"
>  #include "psb_drv.h"
>  #include "psb_intel_drv.h"
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 83485ab81ce8..9872ba9abf1a 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -15,6 +15,7 @@
>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "mgag200_drv.h"
>
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> index b90aa5c1f90a..07acb36235cd 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> @@ -26,6 +26,7 @@
>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "nouveau_drm.h"
>  #include "nouveau_reg.h"
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index fdb3e1adea1e..a1fd99589ce3 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -26,6 +26,7 @@
>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include <drm/drm_dp_helper.h>
>
>  #include <nvif/class.h>
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 2d28dc337cfb..b0566a1ca28f 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -20,6 +20,7 @@
>  #include "omap_drv.h"
>
>  #include <drm/drm_mode.h>
> +#include <drm/drm_plane_helper.h>
>  #include "drm_crtc.h"
>  #include "drm_crtc_helper.h"
>
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index af9e78546688..b7b728e758b8 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -29,6 +29,7 @@
>  #include "qxl_drv.h"
>  #include "qxl_object.h"
>  #include "drm_crtc_helper.h"
> +#include <drm/drm_plane_helper.h>
>
>  static bool qxl_head_enabled(struct qxl_head *head)
>  {
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index 4eb37976f879..ad24536ee4ce 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -32,6 +32,7 @@
>
>  #include <linux/pm_runtime.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include <drm/drm_edid.h>
>
>  #include <linux/gcd.h>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 148b50589181..088bfd875d29 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -19,6 +19,7 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "rcar_du_crtc.h"
>  #include "rcar_du_drv.h"
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 0ddce4d046d9..859ccb658601 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -19,6 +19,7 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include <video/sh_mobile_meram.h>
>
> diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
> index d2ae0c0e13be..36a1ad3c4823 100644
> --- a/drivers/gpu/drm/sti/sti_drm_crtc.c
> +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
> @@ -10,6 +10,7 @@
>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "sti_compositor.h"
>  #include "sti_drm_drv.h"
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 6553fd238685..7bca8ed47e51 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -10,6 +10,7 @@
>  #include <linux/clk.h>
>  #include <linux/debugfs.h>
>  #include <linux/reset.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "dc.h"
>  #include "drm.h"
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index d642d4a02134..29ec98baffd1 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -16,6 +16,7 @@
>   */
>
>  #include "drm_flip_work.h"
> +#include <drm/drm_plane_helper.h>
>
>  #include "tilcdc_drv.h"
>  #include "tilcdc_regs.h"
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index dc145d320b25..1701f1dfb23f 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -14,6 +14,7 @@
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include "udl_drv.h"
>
>  /*
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index 15e185ae4c99..5c289f748ab4 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -26,6 +26,7 @@
>   **************************************************************************/
>
>  #include "vmwgfx_kms.h"
> +#include <drm/drm_plane_helper.h>
>
>
>  #define vmw_crtc_to_ldu(x) \
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index b295463a60b3..7dc591d04d9a 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -26,6 +26,7 @@
>   **************************************************************************/
>
>  #include "vmwgfx_kms.h"
> +#include <drm/drm_plane_helper.h>
>
>
>  #define vmw_crtc_to_sou(x) \
> diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
> index 9cb222e2996f..2f8007241734 100644
> --- a/drivers/staging/imx-drm/imx-drm-core.c
> +++ b/drivers/staging/imx-drm/imx-drm-core.c
> @@ -24,6 +24,7 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_gem_cma_helper.h>
>  #include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
>
>  #include "imx-drm.h"
>
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 36a5cbc0cc73..44c57d2a64ec 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -885,9 +885,6 @@ extern int drm_crtc_init_with_planes(struct drm_device *dev,
>       struct drm_plane *primary,
>       struct drm_plane *cursor,
>       const struct drm_crtc_funcs *funcs);
> -extern int drm_crtc_init(struct drm_device *dev,
> - struct drm_crtc *crtc,
> - const struct drm_crtc_funcs *funcs);
>  extern void drm_crtc_cleanup(struct drm_crtc *crtc);
>  extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
>
> diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> index 52e6870534b2..0e1dcb163b81 100644
> --- a/include/drm/drm_plane_helper.h
> +++ b/include/drm/drm_plane_helper.h
> @@ -42,6 +42,10 @@
>   * planes.
>   */
>
> +extern int drm_crtc_init(struct drm_device *dev,
> + struct drm_crtc *crtc,
> + const struct drm_crtc_funcs *funcs);
> +
>  extern int drm_plane_helper_check_update(struct drm_plane *plane,
>   struct drm_crtc *crtc,
>   struct drm_framebuffer *fb,
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc
  2014-11-02 13:19 ` [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc Daniel Vetter
@ 2014-11-04 20:31   ` Sean Paul
  2014-11-05 16:18   ` Thierry Reding
  1 sibling, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-04 20:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:17PM +0100, Daniel Vetter wrote:
> I've forgotten to do this in:
>
> commit cb597bb3a2fbfc871cc1c703fb330d247bd21394
> Author: Daniel Vetter <daniel.vetter@ffwll.ch>
> Date:   Sun Jul 27 19:09:33 2014 +0200
>
>     drm: trylock modest locking for fbdev panics
>
> Oops, fix this asap.
>
> In my defense kerneldoc is really awful and there's no way it can pick
> up structured comments per struct member. Which means we need both
> since people won't scroll up even a few lines.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  include/drm/drm_modeset_lock.h | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
> index 75a5c45e21c7..28931a23d96c 100644
> --- a/include/drm/drm_modeset_lock.h
> +++ b/include/drm/drm_modeset_lock.h
> @@ -33,6 +33,7 @@ struct drm_modeset_lock;
>   * @ww_ctx: base acquire ctx
>   * @contended: used internally for -EDEADLK handling
>   * @locked: list of held locks
> + * @trylock_only: trylock mode used in atomic contexts/panic notifiers
>   *
>   * Each thread competing for a set of locks must use one acquire
>   * ctx.  And if any lock fxn returns -EDEADLK, it must backoff and
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 05/17] drm: Add atomic driver interface definitions for objects
  2014-11-02 13:19 ` [PATCH 05/17] drm: Add atomic driver interface definitions for objects Daniel Vetter
@ 2014-11-04 20:31   ` Sean Paul
  2014-11-05 16:26   ` Thierry Reding
  1 sibling, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-04 20:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:18PM +0100, Daniel Vetter wrote:
> Heavily based upon Rob Clark's atomic series.
> - Dropped the connctor state from the crtc state, instead opting for a

nit: s/connctor/connector/

>   full-blown connector state. The only thing it has is the desired
>   crtc, but drivers which have connector properties have now a
>   data-structure to subclass.
>
> - Rename create_state to duplicate_state. Especially for legacy ioctls
>   we want updates on top of existing state, so we need a way to get at
>   the current state. We need to be careful to clear the backpointers
>   to the global state correctly though.
>
> - Drop property values. Drivers with properties simply need to
>   subclass the datastructures and track the decoded values in there. I
>   also think that common properties (like rotation) should be decoded
>   and stored in the core structures.
>
> - Create a new set of ->atomic_set_prop functions, for smoother
>   transitions from legacy to atomic operations.
>
> - Pass the ->atomic_set_prop ioctl the right structure to avoid
>   chasing pointers in drivers.
>
> - Drop temporary boolean state for now until we resurrect them with
>   the helper functions.
>
> - Drop invert_dimensions. For now we don't need any checking since
>   that's done by the higher-level legacy ioctls. But even then we
>   should also add rotation/flip tracking to the core drm_crtc_state,
>   not just whether the dimensions are inverted.
>
> - Track crtc state with an enable/disable. That's equivalent to
>   mode_valid, but a bit clearer that it means the entire crtc.
>
> The global interface will follow in subsequent patches.
>
> v2: We need to allow drivers to somehow set up the initial state and
> clear it on resume. So add a plane->reset callback for that. Helpers
> will be provided with default behaviour for all these.
>
> v3: Split out the plane->reset into a separate patch.
>
> v4: Improve kerneldoc in drm_crtc.h
>
> v5: Remove unused inline functions for handling state objects, those
> callbacks are now mandatory for full atomic support.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  include/drm/drm_crtc.h | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 107 insertions(+)
>
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index a68e02be7e37..9847009ad451 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -224,6 +224,25 @@ struct drm_encoder;
>  struct drm_pending_vblank_event;
>  struct drm_plane;
>  struct drm_bridge;
> +struct drm_atomic_state;
> +
> +/**
> + * struct drm_crtc_state - mutable crtc state
> + * @enable: whether the CRTC should be enabled, gates all other state
> + * @mode: current mode timings
> + * @event: optional pointer to a DRM event to signal upon completion of the
> + * state update
> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_crtc_state {
> + bool enable        : 1;
> +
> + struct drm_display_mode mode;
> +
> + struct drm_pending_vblank_event *event;
> +
> + struct drm_atomic_state *state;
> +};
>
>  /**
>   * struct drm_crtc_funcs - control CRTCs for a given device
> @@ -238,6 +257,9 @@ struct drm_bridge;
>   * @set_property: called when a property is changed
>   * @set_config: apply a new CRTC configuration
>   * @page_flip: initiate a page flip
> + * @atomic_duplicate_state: duplicate the atomic state for this CRTC
> + * @atomic_destroy_state: destroy an atomic state for this CRTC
> + * @atomic_set_property: set a property on an atomic state for this CRTC
>   *
>   * The drm_crtc_funcs structure is the central CRTC management structure
>   * in the DRM.  Each CRTC controls one or more connectors (note that the name
> @@ -288,6 +310,15 @@ struct drm_crtc_funcs {
>
>   int (*set_property)(struct drm_crtc *crtc,
>      struct drm_property *property, uint64_t val);
> +
> + /* atomic update handling */
> + struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
> + void (*atomic_destroy_state)(struct drm_crtc *crtc,
> +     struct drm_crtc_state *cstate);
> + int (*atomic_set_property)(struct drm_crtc *crtc,
> +   struct drm_crtc_state *state,
> +   struct drm_property *property,
> +   uint64_t val);
>  };
>
>  /**
> @@ -317,6 +348,7 @@ struct drm_crtc_funcs {
>   * @pixeldur_ns: precise pixel timing
>   * @helper_private: mid-layer private data
>   * @properties: property tracking for this CRTC
> + * @state: current atomic state for this CRTC
>   * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
>   * legacy ioctls
>   *
> @@ -374,6 +406,8 @@ struct drm_crtc {
>
>   struct drm_object_properties properties;
>
> + struct drm_crtc_state *state;
> +
>   /*
>   * For legacy crtc ioctls so that atomic drivers can get at the locking
>   * acquire context.
> @@ -381,6 +415,16 @@ struct drm_crtc {
>   struct drm_modeset_acquire_ctx *acquire_ctx;
>  };
>
> +/**
> + * struct drm_connector_state - mutable connector state
> + * @crtc: crtc to connect connector to, NULL if disabled
> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_connector_state {
> + struct drm_crtc *crtc;
> +
> + struct drm_atomic_state *state;
> +};
>
>  /**
>   * struct drm_connector_funcs - control connectors on a given device
> @@ -393,6 +437,10 @@ struct drm_crtc {
>   * @set_property: property for this connector may need an update
>   * @destroy: make object go away
>   * @force: notify the driver that the connector is forced on
> + * @atomic_duplicate_state: duplicate the atomic state for this connector
> + * @atomic_destroy_state: destroy an atomic state for this connector
> + * @atomic_set_property: set a property on an atomic state for this connector
> + *
>   *
>   * Each CRTC may have one or more connectors attached to it.  The functions
>   * below allow the core DRM code to control connectors, enumerate available modes,
> @@ -417,6 +465,15 @@ struct drm_connector_funcs {
>       uint64_t val);
>   void (*destroy)(struct drm_connector *connector);
>   void (*force)(struct drm_connector *connector);
> +
> + /* atomic update handling */
> + struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
> + void (*atomic_destroy_state)(struct drm_connector *connector,
> +     struct drm_connector_state *cstate);
> + int (*atomic_set_property)(struct drm_connector *connector,
> +   struct drm_connector_state *state,
> +   struct drm_property *property,
> +   uint64_t val);
>  };
>
>  /**
> @@ -515,6 +572,7 @@ struct drm_encoder {
>   * @null_edid_counter: track sinks that give us all zeros for the EDID
>   * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
>   * @debugfs_entry: debugfs directory for this connector
> + * @state: current atomic state for this connector
>   *
>   * Each connector may be connected to one or more CRTCs, or may be clonable by
>   * another connector if they can share a CRTC.  Each connector also has a specific
> @@ -575,8 +633,42 @@ struct drm_connector {
>   unsigned bad_edid_counter;
>
>   struct dentry *debugfs_entry;
> +
> + struct drm_connector_state *state;
> +};
> +
> +/**
> + * struct drm_plane_state - mutable plane state
> + * @crtc: currently bound CRTC, NULL if disabled
> + * @fb: currently bound fb
> + * @crtc_x: left position of visible portion of plane on crtc
> + * @crtc_y: upper position of visible portion of plane on crtc
> + * @crtc_w: width of visible portion of plane on crtc
> + * @crtc_h: height of visible portion of plane on crtc
> + * @src_x: left position of visible portion of plane within
> + * plane (in 16.16)
> + * @src_y: upper position of visible portion of plane within
> + * plane (in 16.16)
> + * @src_w: width of visible portion of plane (in 16.16)
> + * @src_h: height of visible portion of plane (in 16.16)
> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_plane_state {
> + struct drm_crtc *crtc;
> + struct drm_framebuffer *fb;
> +
> + /* Signed dest location allows it to be partially off screen */
> + int32_t crtc_x, crtc_y;
> + uint32_t crtc_w, crtc_h;
> +
> + /* Source values are 16.16 fixed point */
> + uint32_t src_x, src_y;
> + uint32_t src_h, src_w;
> +
> + struct drm_atomic_state *state;
>  };
>
> +
>  /**
>   * struct drm_plane_funcs - driver plane control functions
>   * @update_plane: update the plane configuration
> @@ -584,6 +676,9 @@ struct drm_connector {
>   * @destroy: clean up plane resources
>   * @reset: reset plane after state has been invalidated (e.g. resume)
>   * @set_property: called when a property is changed
> + * @atomic_duplicate_state: duplicate the atomic state for this plane
> + * @atomic_destroy_state: destroy an atomic state for this plane
> + * @atomic_set_property: set a property on an atomic state for this plane
>   */
>  struct drm_plane_funcs {
>   int (*update_plane)(struct drm_plane *plane,
> @@ -598,6 +693,15 @@ struct drm_plane_funcs {
>
>   int (*set_property)(struct drm_plane *plane,
>      struct drm_property *property, uint64_t val);
> +
> + /* atomic update handling */
> + struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
> + void (*atomic_destroy_state)(struct drm_plane *plane,
> +     struct drm_plane_state *cstate);
> + int (*atomic_set_property)(struct drm_plane *plane,
> +   struct drm_plane_state *state,
> +   struct drm_property *property,
> +   uint64_t val);
>  };
>
>  enum drm_plane_type {
> @@ -621,6 +725,7 @@ enum drm_plane_type {
>   * @funcs: helper functions
>   * @properties: property tracking for this plane
>   * @type: type of plane (overlay, primary, cursor)
> + * @state: current atomic state for this plane
>   */
>  struct drm_plane {
>   struct drm_device *dev;
> @@ -642,6 +747,8 @@ struct drm_plane {
>   struct drm_object_properties properties;
>
>   enum drm_plane_type type;
> +
> + struct drm_plane_state *state;
>  };
>
>  /**
> --
> 2.1.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 06/17] drm: Global atomic state handling
  2014-11-04 20:31   ` Sean Paul
@ 2014-11-04 21:30     ` Daniel Vetter
  2014-11-04 21:41       ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 21:30 UTC (permalink / raw)
  To: Sean Paul
  Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu, DRI Development

On Tue, Nov 04, 2014 at 03:31:07PM -0500, Sean Paul wrote:
> On Sun, Nov 02, 2014 at 02:19:19PM +0100, Daniel Vetter wrote:
> > +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> > +  struct drm_crtc *crtc)
> > +{
> > + struct drm_crtc_state *crtc_state;
> > +
> > + crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
> > + if (IS_ERR(crtc_state))
> > + return PTR_ERR(crtc_state);
> > +
> > + conn_state->crtc = crtc;
> > +
> > + DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
> > +      conn_state, crtc->base.id);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
> 
> In drm_atomic_helper.c, you're assigning directly to conn_state->crtc. I think
> you should probably be using this helper (as it doesn't seem to be used
> anywhere). I realize this happens in a different patch, but I want to make sure
> I don't miss it later :-)

Indeed this is a bug, and I didn't catch it because I couldn't test
connector stealing. Scenario:

Connector A is active on CRTC 0.

Userspace does a legacy setCrtc with connector A and CRTC 1.

-> We should steal the connector and disable CRTC 0 (since it doesn't have
any other connectors) completely. But because the helpers didn't pull in
the state for CRTC this doesn't happen.

> If that is the case, I think this could also benefit from the !crtc checks the
> plane equivalent has.

Yup, otherwise helpers need to check for that. I'll fix both and all the
nits you've spotted, too.
-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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH] drm: Global atomic state handling
  2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
  2014-11-03 23:41   ` Matt Roper
  2014-11-04 20:31   ` Sean Paul
@ 2014-11-04 21:37   ` Daniel Vetter
  2014-11-04 22:07     ` Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 21:37 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

v13: Review from Sean:
- kerneldoc spelling fixes
- Don't overallocate states->planes.
- Handle NULL crtc in set_crtc_for_connector.

Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/Makefile     |   2 +-
 drivers/gpu/drm/drm_atomic.c | 594 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h     |  63 +++++
 include/drm/drm_crtc.h       |  35 +++
 4 files changed, 693 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9292a761ea6d..c5e37dc459ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..bf3cdc2133e4
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->planes), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This function returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This function returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This function returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	conn_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+			      conn_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
+			      conn_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async configuration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..753812034e71
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+				  struct drm_crtc *crtc);
+int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				      struct drm_crtc *crtc);
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int drm_atomic_check_only(struct drm_atomic_state *state);
+int drm_atomic_commit(struct drm_atomic_state *state);
+int drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3554868dbf09..07c88ad64234 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -794,6 +794,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+       struct drm_device *dev;
+       uint32_t flags;
+       struct drm_plane **planes;
+       struct drm_plane_state **plane_states;
+       struct drm_crtc **crtcs;
+       struct drm_crtc_state **crtc_states;
+       struct drm_connector **connectors;
+       struct drm_connector_state **connector_states;
+
+       struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -824,6 +850,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -833,6 +862,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

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

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

* Re: [PATCH 06/17] drm: Global atomic state handling
  2014-11-04 21:30     ` Daniel Vetter
@ 2014-11-04 21:41       ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 21:41 UTC (permalink / raw)
  To: Sean Paul
  Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu, DRI Development

On Tue, Nov 04, 2014 at 10:30:37PM +0100, Daniel Vetter wrote:
> On Tue, Nov 04, 2014 at 03:31:07PM -0500, Sean Paul wrote:
> > On Sun, Nov 02, 2014 at 02:19:19PM +0100, Daniel Vetter wrote:
> > > +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> > > +  struct drm_crtc *crtc)
> > > +{
> > > + struct drm_crtc_state *crtc_state;
> > > +
> > > + crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
> > > + if (IS_ERR(crtc_state))
> > > + return PTR_ERR(crtc_state);
> > > +
> > > + conn_state->crtc = crtc;
> > > +
> > > + DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
> > > +      conn_state, crtc->base.id);
> > > +
> > > + return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
> > 
> > In drm_atomic_helper.c, you're assigning directly to conn_state->crtc. I think
> > you should probably be using this helper (as it doesn't seem to be used
> > anywhere). I realize this happens in a different patch, but I want to make sure
> > I don't miss it later :-)
> 
> Indeed this is a bug, and I didn't catch it because I couldn't test
> connector stealing. Scenario:
> 
> Connector A is active on CRTC 0.
> 
> Userspace does a legacy setCrtc with connector A and CRTC 1.
> 
> -> We should steal the connector and disable CRTC 0 (since it doesn't have
> any other connectors) completely. But because the helpers didn't pull in
> the state for CRTC this doesn't happen.

Actually there's a very good chance we'll get away: If we steal the
connector we'll likely also steal its old encoder, and the encoder
stealing already grabs the crtc on its own. Still, better safe than sorry.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm/atomic: Refcounting for plane_state->fb
  2014-11-02 13:19 ` [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb Daniel Vetter
@ 2014-11-04 21:57   ` Daniel Vetter
  2014-11-06 17:44   ` [PATCH 17/17] " Sean Paul
  1 sibling, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 21:57 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter

So my original plan was that the drm core refcounts framebuffers like
with the legacy ioctls. But that doesn't work for a bunch of reasons:

- State objects might live longer than until the next fb change
  happens for a plane. For example delayed cleanup work only happens
  _after_ the pageflip ioctl has completed. So this definitely doesn't
  work without the plane state holding its own refernces.

- The other issue is transition from legacy to atomic implementations,
  where the driver works under a mix of both worlds. Which means
  legacy paths might not properly update the ->fb pointer under
  plane->state->fb. Which is a bit a problem when then someone comes
  around and _does_ try to clean it up when it's long gone.

The second issue is just a bit a transition bug, since drivers should
update plane->state->fb in all the paths that aren't converted yet.
But a bit more robustness for the transition cant' hurt - we pull
similar tricks with cleaning up the old fb in the transitional helpers
already.

The pattern for drivers that transition is

	if (plane->state)
		drm_atomic_set_fb_for_plane(plane->state, plane->fb);

inserted after the fb update has logically completed at the end of
->set_config (or ->set_base/mode_set if using the crtc helpers),
->page_flip, ->update_plane or any other entry point which updates
plane->fb.

v2: Update kerneldoc - copypasta fail.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/drm_atomic.c        | 28 ++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++++++++++------
 drivers/gpu/drm/drm_crtc_helper.c   |  7 ++++---
 drivers/gpu/drm/drm_plane_helper.c  | 14 +++++++-------
 include/drm/drm_atomic.h            |  2 ++
 5 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index bf3cdc2133e4..b71e9200b23d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -366,6 +366,34 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
 
 /**
+ * drm_atomic_set_fb_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @fb: fb to use for the plane
+ *
+ * Changing the assigned framebuffer for a plane requires us to grab a reference
+ * to the new fb and drop the reference to the old fb, if there is one. This
+ * function takes care of all these details besides updating the pointer in the
+ * state object itself.
+ */
+void
+drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+			    struct drm_framebuffer *fb)
+{
+	if (plane_state->fb)
+		drm_framebuffer_unreference(plane_state->fb);
+	if (fb)
+		drm_framebuffer_reference(fb);
+	plane_state->fb = fb;
+
+	if (fb)
+		DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n",
+			      fb->base.id, plane_state);
+	else
+		DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state);
+}
+EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
+
+/**
  * drm_atomic_set_crtc_for_connector - set crtc for connector
  * @conn_state: atomic state object for the connector
  * @crtc: crtc to use for the connector
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bbc41c9b3cfc..851cc6c04b22 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1175,7 +1175,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, crtc);
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 	plane_state->crtc_x = crtc_x;
 	plane_state->crtc_y = crtc_y;
 	plane_state->crtc_h = crtc_h;
@@ -1242,7 +1242,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, NULL);
-	plane_state->fb = NULL;
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
 	plane_state->crtc_h = 0;
@@ -1402,7 +1402,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(primary_state, crtc);
-	primary_state->fb = set->fb;
+	drm_atomic_set_fb_for_plane(primary_state, set->fb);
 	primary_state->crtc_x = 0;
 	primary_state->crtc_y = 0;
 	primary_state->crtc_h = set->mode->vdisplay;
@@ -1695,7 +1695,7 @@ retry:
 	}
 
 	drm_atomic_set_crtc_for_plane(plane_state, crtc);
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 
 	ret = drm_atomic_async_commit(state);
 	if (ret == -EDEADLK)
@@ -1809,6 +1809,9 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
  */
 void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 {
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
 	kfree(plane->state);
 	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
 }
@@ -1824,10 +1827,17 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
 {
+	struct drm_plane_state *state;
+
 	if (WARN_ON(!plane->state))
 		return NULL;
 
-	return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+	state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+
+	if (state && state->fb)
+		drm_framebuffer_reference(state->fb);
+
+	return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 
@@ -1840,8 +1850,11 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
  * subclassed plane state structure.
  */
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
-					  struct drm_plane_state *state)
+					   struct drm_plane_state *state)
 {
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
+
 	kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 33195e9adaab..d552708409de 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -34,11 +34,13 @@
 #include <linux/moduleparam.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 
 /**
@@ -998,15 +1000,14 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = crtc;
-	plane_state->fb = crtc->primary->fb;
+	drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
 	plane_state->crtc_h = crtc->mode.vdisplay;
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index df69522b1f0e..497104df112b 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -27,7 +27,9 @@
 #include <drm/drmP.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -462,7 +464,7 @@ fail:
 		if (plane->funcs->atomic_destroy_state)
 			plane->funcs->atomic_destroy_state(plane, plane_state);
 		else
-			kfree(plane_state);
+			drm_atomic_helper_plane_destroy_state(plane, plane_state);
 	}
 
 	return ret;
@@ -503,15 +505,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = crtc;
-	plane_state->fb = fb;
+	drm_atomic_set_fb_for_plane(plane_state, fb);
 	plane_state->crtc_x = crtc_x;
 	plane_state->crtc_y = crtc_y;
 	plane_state->crtc_h = crtc_h;
@@ -550,15 +551,14 @@ int drm_plane_helper_disable(struct drm_plane *plane)
 	if (plane->funcs->atomic_duplicate_state)
 		plane_state = plane->funcs->atomic_duplicate_state(plane);
 	else if (plane->state)
-		plane_state = kmemdup(plane->state, sizeof(*plane_state),
-				      GFP_KERNEL);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
 	else
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
 
 	plane_state->crtc = NULL;
-	plane_state->fb = NULL;
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
 
 	return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 753812034e71..52d92981209f 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -45,6 +45,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 
 int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 				  struct drm_crtc *crtc);
+void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+				 struct drm_framebuffer *fb);
 int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 				      struct drm_crtc *crtc);
 int
-- 
2.1.1

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

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

* [PATCH] drm: Global atomic state handling
  2014-11-04 21:37   ` [PATCH] " Daniel Vetter
@ 2014-11-04 22:07     ` Daniel Vetter
  2014-11-04 22:32       ` Sean Paul
                         ` (2 more replies)
  0 siblings, 3 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 22:07 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

v13: Review from Sean:
- kerneldoc spelling fixes
- Don't overallocate states->planes.
- Handle NULL crtc in set_crtc_for_connector.

v14: Sprinkle __must_check over all functions which do wait/wound
locking to make sure callers don't forget this. Since I have ;-)

Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

fixup for global atomic state handling
---
 drivers/gpu/drm/Makefile     |   2 +-
 drivers/gpu/drm/drm_atomic.c | 594 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h     |  65 +++++
 include/drm/drm_crtc.h       |  35 +++
 4 files changed, 695 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9292a761ea6d..c5e37dc459ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..bf3cdc2133e4
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->planes), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This function returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This function returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This function returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	conn_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+			      conn_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
+			      conn_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async configuration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..5bb15f550c42
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state * __must_check
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state * __must_check
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state * __must_check
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state * __must_check
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int __must_check
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc);
+int __must_check
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc);
+int __must_check
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
+int __must_check drm_atomic_commit(struct drm_atomic_state *state);
+int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3554868dbf09..07c88ad64234 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -794,6 +794,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+       struct drm_device *dev;
+       uint32_t flags;
+       struct drm_plane **planes;
+       struct drm_plane_state **plane_states;
+       struct drm_crtc **crtcs;
+       struct drm_crtc_state **crtc_states;
+       struct drm_connector **connectors;
+       struct drm_connector_state **connector_states;
+
+       struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -824,6 +850,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -833,6 +862,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

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

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

* [PATCH] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-02 13:19 ` [PATCH 11/17] drm/atomic-helper: implementatations for legacy interfaces Daniel Vetter
@ 2014-11-04 22:08   ` Daniel Vetter
  2014-11-05 13:46     ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 22:08 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Vetter, Intel Graphics Development, Daniel Thompson

Well, except page_flip since that requires async commit, which isn't
there yet.

For the functions which changes planes there's a bit of trickery
involved to keep the fb refcounting working. But otherwise fairly
straight-forward atomic updates.

The property setting functions are still a bit incomplete. Once we
have generic properties (e.g. rotation, but also all the properties
needed by the atomic ioctl) we need to filter those out and parse them
in the helper. Preferrably with the same function as used by the real
atomic ioctl implementation.

v2: Fixup kerneldoc, reported by Paulo.

v3: Add missing EXPORT_SYMBOL.

v4: We need to look at the crtc of the modeset, not some random
leftover one from a previous loop when udpating the connector->crtc
routing. Also push some local variables into inner loops to avoid
these kinds of bugs.

v5: Adjust semantics - drivers now own the atomic state upon
successfully synchronous commit.

v6: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v7:
- Improve comments.
- Filter out the crtc of the ->set_config call when recomputing
  crtc_state->enabled: We should compute the same state, but not doing
  so will give us a good chance to catch bugs and inconsistencies -
  the atomic helper's atomic_check function re-validates this again.
- Fix the set_config implementation logic when disabling the crtc: We
  still need to update the output routing to disable all the
  connectors properly in the state. Caught by the atomic_check
  functions, so at least that part worked ;-) Also add some WARN_ONs
  to ensure ->set_config preconditions all apply.

v8: Fixup an embarrassing h/vdisplay mixup.

v9: Shuffled bad squash to the right patch, spotted by Daniel

v10: Use set_crtc_for_connector as suggested by Sean.

Cc: Sean Paul <seanpaul@chromium.org>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 529 +++++++++++++++++++++++++++++++++++-
 include/drm/drm_atomic_helper.h     |  21 ++
 2 files changed, 549 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 887e1971c915..86b12a1820d0 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -86,6 +86,7 @@ steal_encoder(struct drm_atomic_state *state,
 	struct drm_crtc_state *crtc_state;
 	struct drm_connector *connector;
 	struct drm_connector_state *connector_state;
+	int ret;
 
 	/*
 	 * We can only steal an encoder coming from a connector, which means we
@@ -116,7 +117,9 @@ steal_encoder(struct drm_atomic_state *state,
 		if (IS_ERR(connector_state))
 			return PTR_ERR(connector_state);
 
-		connector_state->crtc = NULL;
+		ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
+		if (ret)
+			return ret;
 		connector_state->best_encoder = NULL;
 	}
 
@@ -1045,3 +1048,527 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
+
+/**
+ * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	if (ret == -EDEADLK)
+		goto backoff;
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_update_plane);
+
+/**
+ * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic
+ * @plane: plane to disable
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_disable_plane(struct drm_plane *plane)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+	if (ret == -EDEADLK)
+		goto backoff;
+	plane_state->fb = NULL;
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_h = 0;
+	plane_state->crtc_w = 0;
+	plane_state->src_x = 0;
+	plane_state->src_y = 0;
+	plane_state->src_h = 0;
+	plane_state->src_w = 0;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_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_connector_state *conn_state;
+	int nconnectors = state->dev->mode_config.num_connector;
+	int ncrtcs = state->dev->mode_config.num_crtc;
+	int ret, i, j;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	/* First grab all affected connector/crtc states. */
+	for (i = 0; i < set->num_connectors; i++) {
+		conn_state = drm_atomic_get_connector_state(state,
+							    set->connectors[i]);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		ret = drm_atomic_add_affected_connectors(state, crtc);
+		if (ret)
+			return ret;
+	}
+
+	/* Then recompute connector->crtc links and crtc enabling state. */
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+
+		connector = state->connectors[i];
+		conn_state = state->connector_states[i];
+
+		if (!connector)
+			continue;
+
+		if (conn_state->crtc == set->crtc) {
+			ret = drm_atomic_set_crtc_for_connector(conn_state,
+								NULL);
+			if (ret)
+				return ret;
+		}
+
+		for (j = 0; j < set->num_connectors; j++) {
+			if (set->connectors[j] == connector) {
+				ret = drm_atomic_set_crtc_for_connector(conn_state,
+									set->crtc);
+				if (ret)
+					return ret;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+		struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+		if (!crtc && crtc != set->crtc)
+			continue;
+
+		crtc_state->enable =
+			drm_atomic_connectors_for_crtc(state, crtc);
+	}
+
+	return 0;
+}
+
+/**
+ * drm_atomic_helper_set_config - set a new config from userspace
+ * @set: mode set configuration
+ *
+ * Provides a default crtc set_config handler using the atomic driver interface.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_set_config(struct drm_mode_set *set)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc *crtc = set->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane_state *primary_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	if (!set->mode) {
+		WARN_ON(set->fb);
+		WARN_ON(set->num_connectors);
+
+		crtc_state->enable = false;
+		goto commit;
+	}
+
+	WARN_ON(!set->fb);
+	WARN_ON(!set->num_connectors);
+
+	crtc_state->enable = true;
+	drm_mode_copy(&crtc_state->mode, set->mode);
+
+	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+	if (IS_ERR(primary_state)) {
+		ret = PTR_ERR(primary_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
+	if (ret == -EDEADLK)
+		goto backoff;
+	primary_state->fb = set->fb;
+	primary_state->crtc_x = 0;
+	primary_state->crtc_y = 0;
+	primary_state->crtc_h = set->mode->vdisplay;
+	primary_state->crtc_w = set->mode->hdisplay;
+	primary_state->src_x = set->x << 16;
+	primary_state->src_y = set->y << 16;
+	primary_state->src_h = set->mode->vdisplay << 16;
+	primary_state->src_w = set->mode->hdisplay << 16;
+
+commit:
+	ret = update_output_state(state, set);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	crtc->primary->old_fb = crtc->primary->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_set_config);
+
+/**
+ * drm_atomic_helper_crtc_set_property - helper for crtc prorties
+ * @crtc: DRM crtc
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
+
+/**
+ * drm_atomic_helper_plane_set_property - helper for plane prorties
+ * @plane: DRM plane
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disable handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = plane->dev->mode_config.acquire_ctx;
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = plane->funcs->atomic_set_property(plane, plane_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+/**
+ * drm_atomic_helper_connector_set_property - helper for connector prorties
+ * @connector: DRM connector
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector_state *connector_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(connector->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = connector->dev->mode_config.acquire_ctx;
+retry:
+	connector_state = drm_atomic_get_connector_state(state, connector);
+	if (IS_ERR(connector_state)) {
+		ret = PTR_ERR(connector_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = connector->funcs->atomic_set_property(connector, connector_state,
+					       property, val);
+	if (ret) {
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful commit. */
+	if (ret == 0)
+		return 0;
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 9781ce739e10..8cd6fe7a48e5 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -49,4 +49,25 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
 void drm_atomic_helper_swap_state(struct drm_device *dev,
 				  struct drm_atomic_state *state);
 
+/* implementations for legacy interfaces */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h);
+int drm_atomic_helper_disable_plane(struct drm_plane *plane);
+int drm_atomic_helper_set_config(struct drm_mode_set *set);
+
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+					struct drm_property *property,
+					uint64_t val);
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm/atomic-helper: implement ->page_flip
  2014-11-02 13:19 ` [PATCH 14/17] drm/atomic-helper: implement ->page_flip Daniel Vetter
@ 2014-11-04 22:09   ` Daniel Vetter
  2014-11-05 11:35     ` Daniel Thompson
  2014-11-05 13:46     ` Daniel Vetter
  2014-11-06 17:43   ` [PATCH 14/17] " Sean Paul
  1 sibling, 2 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 22:09 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Currently there is no way to implement async flips using atomic, that
essentially requires us to be able to cancel pending requests
mid-flight.

To be able to do that (and I guess we want this since vblank synced
updates whic opportunistically cancel still pending updates seem to be
wanted) we'd need to add a mandatory cancellation mode. Depending upon
the exact semantics we decide upon that could mean that userspace will
not get completion events, or will get them all stacked up.

So reject async updates for now. Also async updates usually means not
vblank synced at all, and I guess for drivers which want to support
this they should simply add a special pageflip handler (since usually
you need a special flip cmd to achieve this). That kind of async flip
is pretty much exclusively just used for games and benchmarks where
dropping just one frame means you'll get a headshot or something bad
like that ... And so slight amounts of tearing is acceptable.

v2: Fixup kerneldoc, reported by Paulo.

v3: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v4: Update crtc->primary->fb since ->page_flip is the only driver
callback where the core won't do this itself. We might want to fix
this inconsistency eventually.

v5: Use set_crtc_for_connector as suggested by Sean.

Cc: Sean Paul <seanpaul@chromium.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  5 ++
 2 files changed, 97 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 790edc18b2cb..36ccc42d43db 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1633,3 +1633,95 @@ backoff:
 	goto retry;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
+
+/**
+ * drm_atomic_helper_page_flip - execute a legacy page flip
+ * @crtc: DRM crtc
+ * @fb: DRM framebuffer
+ * @event: optional DRM event to signal upon completion
+ * @flags: flip flags for non-vblank sync'ed updates
+ *
+ * Provides a default page flip implementation using the atomic driver interface.
+ *
+ * Note that for now so called async page flips (i.e. updates which are not
+ * synchronized to vblank) are not supported, since the atomic interfaces have
+ * no provisions for this yet.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags)
+{
+	struct drm_plane *plane = crtc->primary;
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+		return -EINVAL;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+	crtc_state->event = event;
+
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		if (ret == -EDEADLK)
+			goto backoff;
+		else
+			goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	if (ret == -EDEADLK)
+		goto backoff;
+	plane_state->fb = fb;
+
+	ret = drm_atomic_async_commit(state);
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	/* Driver takes ownership of state on successful async commit. */
+	if (ret == 0) {
+		/* TODO: ->page_flip is the only driver callback where the core
+		 * doesn't update plane->fb. For now patch it up here. */
+		plane->fb = plane->state->fb;
+
+		return 0;
+	}
+
+fail:
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_page_flip);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 8cd6fe7a48e5..28a2f3a815fd 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
 int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
 					struct drm_property *property,
 					uint64_t val);
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags);
+
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* Re: [PATCH 07/17] drm: Add atomic/plane helpers
  2014-11-02 13:19 ` [PATCH 07/17] drm: Add atomic/plane helpers Daniel Vetter
@ 2014-11-04 22:30   ` Sean Paul
  2014-11-04 23:16     ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-04 22:30 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:20PM +0100, Daniel Vetter wrote:
> This is the first cut of atomic helper code. As-is it's only useful to
> implement a pure atomic interface for plane updates.
>
> Later patches will integrate this with the crtc helpers so that full
> atomic updates are possible. We also need a pile of helpers to aid
> drivers in transitioning from the legacy world to the shiny new atomic
> age. Finally we need helpers to implement legacy ioctls on top of the
> atomic interface.
>
> The design of the overall helpers<->driver interaction is fairly
> simple, but has an unfortunate large interface:
>
> - We have ->atomic_check callbacks for crtcs and planes. The idea is
>   that connectors don't need any checking, and if they do they can
>   adjust the relevant crtc driver-private state. So no connector hooks
>   should be needed. Also the crtc helpers integration will do the
>   ->best_encoder checks, so no need for that.
>
> - Framebuffer pinning needs to be done before we can commit to the hw
>   state. This is especially important for async updates where we must
>   pin all buffers before returning to userspace, so that really only
>   hw failures can happen in the asynchronous worker.
>
>   Hence we add ->prepare_fb and ->cleanup_fb hooks for this resources
>   management.
>
> - The actual atomic plane commit can't fail (except hw woes), so has
>   void return type. It has three stages:
>   1. Prepare all affected crtcs with crtc->atomic_begin. Drivers can
>      use this to unset the GO bit or similar latches to prevent plane
>      updates.
>   2. Update plane state by looping over all changed planes and calling
>      plane->atomic_update. Presuming the hardware is sane and has GO
>      bits drivers can simply bash the state into the hardware in this
>      function. Other drivers might use this to precompute hw state for
>      the final step.
>   3. Finally latch the update for the next vblank with
>      crtc->atomic_flush. Note that this function doesn't need to wait
>      for the vblank to happen even for the synchronous case.
>
> v2: Clear drm_<obj>_state->state to NULL when swapping in state.
>
> v3: Add TODO that we don't short-circuit plane updates for now. Likely
> no one will care.
>
> v4: Squash in a bit of polish that somehow landed in the wrong (later)
> patche.
>
> v5: Integrate atomic functions into the drm docbook and fixup the
> kerneldoc.
>
> v6: Fixup fixup patch squashing fumble.
>
> v7: Don't touch the legacy plane state plane->fb and plane->crtc. This
> is only used by the legacy ioctl code in the drm core, and that code
> already takes care of updating the pointers in all relevant cases.
> This is in stark contrast to connector->encoder->crtc links on the
> modeset side, which we still need to set since the core doesn't touch
> them.
>
> Also some more kerneldoc polish.
>
> v8: Drop outdated comment.
>
> v9: Handle the state->state pointer correctly: Only clearing the
> ->state pointer when assigning the state to the kms object isn't good
> enough. We also need to re-link the swapped out state into the
> drm_atomic_state structure.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>


Minor nit re: docbook. Otherwise,

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  Documentation/DocBook/drm.tmpl      |   4 +
>  drivers/gpu/drm/Makefile            |   2 +-
>  drivers/gpu/drm/drm_atomic_helper.c | 355 ++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic_helper.h     |  44 +++++
>  include/drm/drm_crtc.h              |   6 +
>  include/drm/drm_crtc_helper.h       |   6 +
>  include/drm/drm_plane_helper.h      |  22 +++
>  7 files changed, 438 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_atomic_helper.c
>  create mode 100644 include/drm/drm_atomic_helper.h
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 89829ae58e97..ea0ef43b19e1 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
>  !Edrivers/gpu/drm/drm_modes.c
>      </sect2>
>      <sect2>
> +      <title>Atomic Mode Setting Function Reference</title>
> +!Edrivers/gpu/drm/drm_atomic.c
> +    </sect2>
> +    <sect2>

This change should probably be in the previous patch.


>        <title>Frame Buffer Creation</title>
>        <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
>       struct drm_file *file_priv,
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 2e89cd50c14f..96338e349a24 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -24,7 +24,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o
>  drm-$(CONFIG_OF) += drm_of.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_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
>  drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>  drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o
>  drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> new file mode 100644
> index 000000000000..55a8eb2678b0
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -0,0 +1,355 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +static void
> +drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
> + struct drm_plane_state *plane_state,
> + struct drm_plane *plane)
> +{
> + struct drm_crtc_state *crtc_state;
> +
> + if (plane->state->crtc) {
> + crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
> +
> + if (WARN_ON(!crtc_state))
> + return;
> +
> + crtc_state->planes_changed = true;
> + }
> +
> + if (plane_state->crtc) {
> + crtc_state =
> + state->crtc_states[drm_crtc_index(plane_state->crtc)];
> +
> + if (WARN_ON(!crtc_state))
> + return;
> +
> + crtc_state->planes_changed = true;
> + }
> +}
> +
> +/**
> + * drm_atomic_helper_check - validate state object
> + * @dev: DRM device
> + * @state: the driver state object
> + *
> + * Check the state object to see if the requested state is physically possible.
> + * Only crtcs and planes have check callbacks, so for any additional (global)
> + * checking that a driver needs it can simply wrap that around this function.
> + * Drivers without such needs can directly use this as their ->atomic_check()
> + * callback.
> + *
> + * RETURNS
> + * Zero for success or -errno
> + */
> +int drm_atomic_helper_check(struct drm_device *dev,
> +    struct drm_atomic_state *state)
> +{
> + int nplanes = dev->mode_config.num_total_plane;
> + int ncrtcs = dev->mode_config.num_crtc;
> + int i, ret = 0;
> +
> + for (i = 0; i < nplanes; i++) {
> + struct drm_plane_helper_funcs *funcs;
> + struct drm_plane *plane = state->planes[i];
> + struct drm_plane_state *plane_state = state->plane_states[i];
> +
> + if (!plane)
> + continue;
> +
> + funcs = plane->helper_private;
> +
> + drm_atomic_helper_plane_changed(state, plane_state, plane);
> +
> + if (!funcs || !funcs->atomic_check)
> + continue;
> +
> + ret = funcs->atomic_check(plane, plane_state);
> + if (ret) {
> + DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n",
> +      plane->base.id);
> + return ret;
> + }
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + if (!funcs || !funcs->atomic_check)
> + continue;
> +
> + ret = funcs->atomic_check(crtc, state->crtc_states[i]);
> + if (ret) {
> + DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n",
> +      crtc->base.id);
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_check);
> +
> +/**
> + * drm_atomic_helper_prepare_planes - prepare plane resources after commit
> + * @dev: DRM device
> + * @state: atomic state object with old state structures
> + *
> + * This function prepares plane state, specifically framebuffers, for the new
> + * configuration. If any failure is encountered this function will call
> + * ->cleanup_fb on any already successfully prepared framebuffer.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_helper_prepare_planes(struct drm_device *dev,
> +     struct drm_atomic_state *state)
> +{
> + int nplanes = dev->mode_config.num_total_plane;
> + int ret, i;
> +
> + for (i = 0; i < nplanes; i++) {
> + struct drm_plane_helper_funcs *funcs;
> + struct drm_plane *plane = state->planes[i];
> + struct drm_framebuffer *fb;
> +
> + if (!plane)
> + continue;
> +
> + funcs = plane->helper_private;
> +
> + fb = state->plane_states[i]->fb;
> +
> + if (fb && funcs->prepare_fb) {
> + ret = funcs->prepare_fb(plane, fb);
> + if (ret)
> + goto fail;
> + }
> + }
> +
> + return 0;
> +
> +fail:
> + for (i--; i >= 0; i--) {
> + struct drm_plane_helper_funcs *funcs;
> + struct drm_plane *plane = state->planes[i];
> + struct drm_framebuffer *fb;
> +
> + if (!plane)
> + continue;
> +
> + funcs = plane->helper_private;
> +
> + fb = state->plane_states[i]->fb;
> +
> + if (fb && funcs->cleanup_fb)
> + funcs->cleanup_fb(plane, fb);
> +
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
> +
> +/**
> + * drm_atomic_helper_commit_planes - commit plane state
> + * @dev: DRM device
> + * @state: atomic state
> + *
> + * This function commits the new plane state using the plane and atomic helper
> + * functions for planes and crtcs. It assumes that the atomic state has already
> + * been pushed into the relevant object state pointers, since this step can no
> + * longer fail.
> + *
> + * It still requires the global state object @state to know which planes and
> + * crtcs need to be updated though.
> + */
> +void drm_atomic_helper_commit_planes(struct drm_device *dev,
> +     struct drm_atomic_state *state)
> +{
> + int nplanes = dev->mode_config.num_total_plane;
> + int ncrtcs = dev->mode_config.num_crtc;
> + int i;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + if (!funcs || !funcs->atomic_begin)
> + continue;
> +
> + funcs->atomic_begin(crtc);
> + }
> +
> + for (i = 0; i < nplanes; i++) {
> + struct drm_plane_helper_funcs *funcs;
> + struct drm_plane *plane = state->planes[i];
> +
> + if (!plane)
> + continue;
> +
> + funcs = plane->helper_private;
> +
> + if (!funcs || !funcs->atomic_update)
> + continue;
> +
> + funcs->atomic_update(plane);
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + if (!funcs || !funcs->atomic_flush)
> + continue;
> +
> + funcs->atomic_flush(crtc);
> + }
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
> +
> +/**
> + * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
> + * @dev: DRM device
> + * @old_state: atomic state object with old state structures
> + *
> + * This function cleans up plane state, specifically framebuffers, from the old
> + * configuration. Hence the old configuration must be perserved in @old_state to
> + * be able to call this function.
> + *
> + * This function must also be called on the new state when the atomic update
> + * fails at any point after calling drm_atomic_helper_prepare_planes().
> + */
> +void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
> +      struct drm_atomic_state *old_state)
> +{
> + int nplanes = dev->mode_config.num_total_plane;
> + int i;
> +
> + for (i = 0; i < nplanes; i++) {
> + struct drm_plane_helper_funcs *funcs;
> + struct drm_plane *plane = old_state->planes[i];
> + struct drm_framebuffer *old_fb;
> +
> + if (!plane)
> + continue;
> +
> + funcs = plane->helper_private;
> +
> + old_fb = old_state->plane_states[i]->fb;
> +
> + if (old_fb && funcs->cleanup_fb)
> + funcs->cleanup_fb(plane, old_fb);
> + }
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
> +
> +/**
> + * drm_atomic_helper_swap_state - store atomic state into current sw state
> + * @dev: DRM device
> + * @state: atomic state
> + *
> + * This function stores the atomic state into the current state pointers in all
> + * driver objects. It should be called after all failing steps have been done
> + * and succeeded, but before the actual hardware state is committed.
> + *
> + * For cleanup and error recovery the current state for all changed objects will
> + * be swaped into @state.
> + *
> + * With that sequence it fits perfectly into the plane prepare/cleanup sequence:
> + *
> + * 1. Call drm_atomic_helper_prepare_planes() with the staged atomic state.
> + *
> + * 2. Do any other steps that might fail.
> + *
> + * 3. Put the staged state into the current state pointers with this function.
> + *
> + * 4. Actually commit the hardware state.
> + *
> + * 5. Call drm_atomic_helper_cleanup_planes with @state, which since step 3
> + * contains the old state. Also do any other cleanup required with that state.
> + */
> +void drm_atomic_helper_swap_state(struct drm_device *dev,
> +  struct drm_atomic_state *state)
> +{
> + int i;
> +
> + for (i = 0; i < dev->mode_config.num_connector; i++) {
> + struct drm_connector *connector = state->connectors[i];
> +
> + if (!connector)
> + continue;
> +
> + connector->state->state = state;
> + swap(state->connector_states[i], connector->state);
> + connector->state->state = NULL;
> + }
> +
> + for (i = 0; i < dev->mode_config.num_crtc; i++) {
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + crtc->state->state = state;
> + swap(state->crtc_states[i], crtc->state);
> + crtc->state->state = NULL;
> + }
> +
> + for (i = 0; i < dev->mode_config.num_total_plane; i++) {
> + struct drm_plane *plane = state->planes[i];
> +
> + if (!plane)
> + continue;
> +
> + plane->state->state = state;
> + swap(state->plane_states[i], plane->state);
> + plane->state->state = NULL;
> + }
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_swap_state);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> new file mode 100644
> index 000000000000..79938c62e7ad
> --- /dev/null
> +++ b/include/drm/drm_atomic_helper.h
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +#ifndef DRM_ATOMIC_HELPER_H_
> +#define DRM_ATOMIC_HELPER_H_
> +
> +int drm_atomic_helper_check(struct drm_device *dev,
> +    struct drm_atomic_state *state);
> +
> +int drm_atomic_helper_prepare_planes(struct drm_device *dev,
> +     struct drm_atomic_state *state);
> +void drm_atomic_helper_commit_planes(struct drm_device *dev,
> +     struct drm_atomic_state *state);
> +void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
> +      struct drm_atomic_state *old_state);
> +
> +void drm_atomic_helper_swap_state(struct drm_device *dev,
> +  struct drm_atomic_state *state);
> +
> +#endif /* DRM_ATOMIC_HELPER_H_ */
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index c3ce5b36da5f..d0068b7af678 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -229,6 +229,7 @@ struct drm_atomic_state;
>  /**
>   * struct drm_crtc_state - mutable crtc state
>   * @enable: whether the CRTC should be enabled, gates all other state
> + * @planes_changed: for use by helpers and drivers when computing state updates
>   * @mode: current mode timings
>   * @event: optional pointer to a DRM event to signal upon completion of the
>   * state update
> @@ -237,6 +238,9 @@ struct drm_atomic_state;
>  struct drm_crtc_state {
>   bool enable        : 1;
>
> + /* computed state bits used by helpers and drivers */
> + bool planes_changed : 1;
> +
>   struct drm_display_mode mode;
>
>   struct drm_pending_vblank_event *event;
> @@ -748,6 +752,8 @@ struct drm_plane {
>
>   enum drm_plane_type type;
>
> + void *helper_private;
> +
>   struct drm_plane_state *state;
>  };
>
> diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
> index a3d75fefd010..adec48b27aa5 100644
> --- a/include/drm/drm_crtc_helper.h
> +++ b/include/drm/drm_crtc_helper.h
> @@ -81,6 +81,12 @@ struct drm_crtc_helper_funcs {
>
>   /* disable crtc when not in use - more explicit than dpms off */
>   void (*disable)(struct drm_crtc *crtc);
> +
> + /* atomic helpers */
> + int (*atomic_check)(struct drm_crtc *crtc,
> +    struct drm_crtc_state *state);
> + void (*atomic_begin)(struct drm_crtc *crtc);
> + void (*atomic_flush)(struct drm_crtc *crtc);
>  };
>
>  /**
> diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> index 0e1dcb163b81..c2146a7d91fb 100644
> --- a/include/drm/drm_plane_helper.h
> +++ b/include/drm/drm_plane_helper.h
> @@ -46,6 +46,28 @@ extern int drm_crtc_init(struct drm_device *dev,
>   struct drm_crtc *crtc,
>   const struct drm_crtc_funcs *funcs);
>
> +/**
> + * drm_plane_helper_funcs - helper operations for CRTCs
> + *
> + * The helper operations are called by the mid-layer CRTC helper.
> + */
> +struct drm_plane_helper_funcs {
> + int (*prepare_fb)(struct drm_plane *plane,
> +  struct drm_framebuffer *fb);
> + void (*cleanup_fb)(struct drm_plane *plane,
> +   struct drm_framebuffer *fb);
> +
> + int (*atomic_check)(struct drm_plane *plane,
> +    struct drm_plane_state *state);
> + void (*atomic_update)(struct drm_plane *plane);
> +};
> +
> +static inline void drm_plane_helper_add(struct drm_plane *plane,
> + const struct drm_plane_helper_funcs *funcs)
> +{
> + plane->helper_private = (void *)funcs;
> +}
> +
>  extern int drm_plane_helper_check_update(struct drm_plane *plane,
>   struct drm_crtc *crtc,
>   struct drm_framebuffer *fb,
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm: Global atomic state handling
  2014-11-04 22:07     ` Daniel Vetter
@ 2014-11-04 22:32       ` Sean Paul
  2014-11-05 13:06       ` Ander Conselvan de Oliveira
  2014-11-05 13:45       ` Daniel Vetter
  2 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-04 22:32 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Fengguang Wu, DRI Development

On Tue, Nov 4, 2014 at 5:07 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> Some differences compared to Rob's patches again:
> - Dropped the committed and checked booleans. Checking will be
>   internally enforced by always calling ->atomic_check before
>   ->atomic_commit. And async handling needs to be solved differently
>   because the current scheme completely side-steps ww mutex deadlock
>   avoidance (and so either reinvents a new deadlock avoidance wheel or
>   like the current code just deadlocks).
>
> - State for connectors needed to be added, since now they have a
>   full-blown drm_connector_state (so that drivers have something to
>   attach their own stuff to).
>
> - Refcounting is gone. I plane to solve async updates differently,
>   since the lock-passing scheme doesn't cut it (since it abuses ww
>   mutexes). Essentially what we need for async is a simple ownership
>   transfer from the caller to the driver. That doesn't need full-blown
>   refcounting.
>
> - The acquire ctx is a pointer. Real atomic callers should have that
>   on their stack, legacy entry points need to put the right one
>   (obtained by drm_modeset_legacy_acuire_ctx) in there.
>
> - I've dropped all hooks except check/commit. All the begin/end
>   handling is done by core functions and is the same.
>
> - commit/check are just thin wrappers that ensure that ->check is
>   always called.
>
> - To help out with locking in the legacy implementations I've added a
>   helper to just grab all locks in the backoff case.
>
> v2: Add notices that check/commit can fail with EDEADLK.
>
> v3:
> - More consistent naming for state_alloc.
> - Add state_clear which is needed for backoff and retry.
>
> v4: Planes/connectors can switch between crtcs, and we need to be
> careful that we grab the state (and locks) for both the old and new
> crtc. Improve the interface functions to ensure this.
>
> v5: Add functions to grab affected connectors for a crtc and to recompute
> the crtc->enable state. This is useful for both helper and atomic ioctl
> code when e.g. removing a connector.
>
> v6: Squash in fixup from Fengguang to use ERR_CAST.
>
> v7: Add debug output.
>
> v8: Make checkpatch happy about kcalloc argument ordering.
>
> v9: Improve kerneldoc in drm_crtc.h
>
> v10:
> - Fix another kcalloc argument misorder I've missed.
> - More polish for kerneldoc.
>
> v11: Clarify the ownership rules for the state object. The new rule is
> that a successful drm_atomic_commit (whether synchronous or asnyc)
> always inherits the state and is responsible for the clean-up. That
> way async and sync ->commit functions are more similar.
>
> v12: A few bugfixes:
> - Assign state->state pointers correctly when grabbing state objects -
>   we need to link them up with the global state.
> - Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
>   for the callers of this function.
>
> v13: Review from Sean:
> - kerneldoc spelling fixes
> - Don't overallocate states->planes.
> - Handle NULL crtc in set_crtc_for_connector.
>
> v14: Sprinkle __must_check over all functions which do wait/wound
> locking to make sure callers don't forget this. Since I have ;-)
>

Thanks for the quick turnaround.

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> Cc: Fengguang Wu <fengguang.wu@intel.com>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Matt Roper <matthew.d.roper@intel.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> fixup for global atomic state handling
> ---
>  drivers/gpu/drm/Makefile     |   2 +-
>  drivers/gpu/drm/drm_atomic.c | 594 +++++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic.h     |  65 +++++
>  include/drm/drm_crtc.h       |  35 +++
>  4 files changed, 695 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/drm_atomic.c
>  create mode 100644 include/drm/drm_atomic.h
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 9292a761ea6d..c5e37dc459ee 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -14,7 +14,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
>                 drm_info.o drm_debugfs.o drm_encoder_slave.o \
>                 drm_trace_points.o drm_global.o drm_prime.o \
>                 drm_rect.o drm_vma_manager.o drm_flip_work.o \
> -               drm_modeset_lock.o
> +               drm_modeset_lock.o drm_atomic.o
>
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> new file mode 100644
> index 000000000000..bf3cdc2133e4
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -0,0 +1,594 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_plane_helper.h>
> +
> +static void kfree_state(struct drm_atomic_state *state)
> +{
> +       kfree(state->connectors);
> +       kfree(state->connector_states);
> +       kfree(state->crtcs);
> +       kfree(state->crtc_states);
> +       kfree(state->planes);
> +       kfree(state->plane_states);
> +       kfree(state);
> +}
> +
> +/**
> + * drm_atomic_state_alloc - allocate atomic state
> + * @dev: DRM device
> + *
> + * This allocates an empty atomic state to track updates.
> + */
> +struct drm_atomic_state *
> +drm_atomic_state_alloc(struct drm_device *dev)
> +{
> +       struct drm_atomic_state *state;
> +
> +       state = kzalloc(sizeof(*state), GFP_KERNEL);
> +       if (!state)
> +               return NULL;
> +
> +       state->crtcs = kcalloc(dev->mode_config.num_crtc,
> +                              sizeof(*state->crtcs), GFP_KERNEL);
> +       if (!state->crtcs)
> +               goto fail;
> +       state->crtc_states = kcalloc(dev->mode_config.num_crtc,
> +                                    sizeof(*state->crtc_states), GFP_KERNEL);
> +       if (!state->crtc_states)
> +               goto fail;
> +       state->planes = kcalloc(dev->mode_config.num_total_plane,
> +                               sizeof(*state->planes), GFP_KERNEL);
> +       if (!state->planes)
> +               goto fail;
> +       state->plane_states = kcalloc(dev->mode_config.num_total_plane,
> +                                     sizeof(*state->plane_states), GFP_KERNEL);
> +       if (!state->plane_states)
> +               goto fail;
> +       state->connectors = kcalloc(dev->mode_config.num_connector,
> +                                   sizeof(*state->connectors),
> +                                   GFP_KERNEL);
> +       if (!state->connectors)
> +               goto fail;
> +       state->connector_states = kcalloc(dev->mode_config.num_connector,
> +                                         sizeof(*state->connector_states),
> +                                         GFP_KERNEL);
> +       if (!state->connector_states)
> +               goto fail;
> +
> +       state->dev = dev;
> +
> +       DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
> +
> +       return state;
> +fail:
> +       kfree_state(state);
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL(drm_atomic_state_alloc);
> +
> +/**
> + * drm_atomic_state_clear - clear state object
> + * @state: atomic state
> + *
> + * When the w/w mutex algorithm detects a deadlock we need to back off and drop
> + * all locks. So someone else could sneak in and change the current modeset
> + * configuration. Which means that all the state assembled in @state is no
> + * longer an atomic update to the current state, but to some arbitrary earlier
> + * state. Which could break assumptions the driver's ->atomic_check likely
> + * relies on.
> + *
> + * Hence we must clear all cached state and completely start over, using this
> + * function.
> + */
> +void drm_atomic_state_clear(struct drm_atomic_state *state)
> +{
> +       struct drm_device *dev = state->dev;
> +       int i;
> +
> +       DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
> +
> +       for (i = 0; i < dev->mode_config.num_connector; i++) {
> +               struct drm_connector *connector = state->connectors[i];
> +
> +               if (!connector)
> +                       continue;
> +
> +               connector->funcs->atomic_destroy_state(connector,
> +                                                      state->connector_states[i]);
> +       }
> +
> +       for (i = 0; i < dev->mode_config.num_crtc; i++) {
> +               struct drm_crtc *crtc = state->crtcs[i];
> +
> +               if (!crtc)
> +                       continue;
> +
> +               crtc->funcs->atomic_destroy_state(crtc,
> +                                                 state->crtc_states[i]);
> +       }
> +
> +       for (i = 0; i < dev->mode_config.num_total_plane; i++) {
> +               struct drm_plane *plane = state->planes[i];
> +
> +               if (!plane)
> +                       continue;
> +
> +               plane->funcs->atomic_destroy_state(plane,
> +                                                  state->plane_states[i]);
> +       }
> +}
> +EXPORT_SYMBOL(drm_atomic_state_clear);
> +
> +/**
> + * drm_atomic_state_free - free all memory for an atomic state
> + * @state: atomic state to deallocate
> + *
> + * This frees all memory associated with an atomic state, including all the
> + * per-object state for planes, crtcs and connectors.
> + */
> +void drm_atomic_state_free(struct drm_atomic_state *state)
> +{
> +       drm_atomic_state_clear(state);
> +
> +       DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
> +
> +       kfree_state(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_state_free);
> +
> +/**
> + * drm_atomic_get_crtc_state - get crtc state
> + * @state: global atomic state object
> + * @crtc: crtc to get state object for
> + *
> + * This function returns the crtc state for the given crtc, allocating it if
> + * needed. It will also grab the relevant crtc lock to make sure that the state
> + * is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_crtc_state *
> +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> +                         struct drm_crtc *crtc)
> +{
> +       int ret, index;
> +       struct drm_crtc_state *crtc_state;
> +
> +       index = drm_crtc_index(crtc);
> +
> +       if (state->crtc_states[index])
> +               return state->crtc_states[index];
> +
> +       ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
> +       if (!crtc_state)
> +               return ERR_PTR(-ENOMEM);
> +
> +       state->crtc_states[index] = crtc_state;
> +       state->crtcs[index] = crtc;
> +       crtc_state->state = state;
> +
> +       DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
> +                     crtc->base.id, crtc_state, state);
> +
> +       return crtc_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_crtc_state);
> +
> +/**
> + * drm_atomic_get_plane_state - get plane state
> + * @state: global atomic state object
> + * @plane: plane to get state object for
> + *
> + * This function returns the plane state for the given plane, allocating it if
> + * needed. It will also grab the relevant plane lock to make sure that the state
> + * is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +                         struct drm_plane *plane)
> +{
> +       int ret, index;
> +       struct drm_plane_state *plane_state;
> +
> +       index = drm_plane_index(plane);
> +
> +       if (state->plane_states[index])
> +               return state->plane_states[index];
> +
> +       /*
> +        * TODO: We currently don't have per-plane mutexes. So instead of trying
> +        * crazy tricks with deferring plane->crtc and hoping for the best just
> +        * grab all crtc locks. Once we have per-plane locks we must update this
> +        * to only take the plane mutex.
> +        */
> +       ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       plane_state = plane->funcs->atomic_duplicate_state(plane);
> +       if (!plane_state)
> +               return ERR_PTR(-ENOMEM);
> +
> +       state->plane_states[index] = plane_state;
> +       state->planes[index] = plane;
> +       plane_state->state = state;
> +
> +       DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> +                     plane->base.id, plane_state, state);
> +
> +       if (plane_state->crtc) {
> +               struct drm_crtc_state *crtc_state;
> +
> +               crtc_state = drm_atomic_get_crtc_state(state,
> +                                                      plane_state->crtc);
> +               if (IS_ERR(crtc_state))
> +                       return ERR_CAST(crtc_state);
> +       }
> +
> +       return plane_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_plane_state);
> +
> +/**
> + * drm_atomic_get_connector_state - get connector state
> + * @state: global atomic state object
> + * @connector: connector to get state object for
> + *
> + * This function returns the connector state for the given connector,
> + * allocating it if needed. It will also grab the relevant connector lock to
> + * make sure that the state is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_connector_state *
> +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> +                         struct drm_connector *connector)
> +{
> +       int ret, index;
> +       struct drm_mode_config *config = &connector->dev->mode_config;
> +       struct drm_connector_state *connector_state;
> +
> +       index = drm_connector_index(connector);
> +
> +       if (state->connector_states[index])
> +               return state->connector_states[index];
> +
> +       ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       connector_state = connector->funcs->atomic_duplicate_state(connector);
> +       if (!connector_state)
> +               return ERR_PTR(-ENOMEM);
> +
> +       state->connector_states[index] = connector_state;
> +       state->connectors[index] = connector;
> +       connector_state->state = state;
> +
> +       DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
> +                     connector->base.id, connector_state, state);
> +
> +       if (connector_state->crtc) {
> +               struct drm_crtc_state *crtc_state;
> +
> +               crtc_state = drm_atomic_get_crtc_state(state,
> +                                                      connector_state->crtc);
> +               if (IS_ERR(crtc_state))
> +                       return ERR_CAST(crtc_state);
> +       }
> +
> +       return connector_state;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_connector_state);
> +
> +/**
> + * drm_atomic_set_crtc_for_plane - set crtc for plane
> + * @plane_state: atomic state object for the plane
> + * @crtc: crtc to use for the plane
> + *
> + * Changing the assigned crtc for a plane requires us to grab the lock and state
> + * for the new crtc, as needed. This function takes care of all these details
> + * besides updating the pointer in the state object itself.
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
> +                             struct drm_crtc *crtc)
> +{
> +       struct drm_crtc_state *crtc_state;
> +
> +       if (crtc) {
> +               crtc_state = drm_atomic_get_crtc_state(plane_state->state,
> +                                                      crtc);
> +               if (IS_ERR(crtc_state))
> +                       return PTR_ERR(crtc_state);
> +       }
> +
> +       plane_state->crtc = crtc;
> +
> +       if (crtc)
> +               DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
> +                             plane_state, crtc->base.id);
> +       else
> +               DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
> +
> +/**
> + * drm_atomic_set_crtc_for_connector - set crtc for connector
> + * @conn_state: atomic state object for the connector
> + * @crtc: crtc to use for the connector
> + *
> + * Changing the assigned crtc for a connector requires us to grab the lock and
> + * state for the new crtc, as needed. This function takes care of all these
> + * details besides updating the pointer in the state object itself.
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> +                                 struct drm_crtc *crtc)
> +{
> +       struct drm_crtc_state *crtc_state;
> +
> +       if (crtc) {
> +               crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
> +               if (IS_ERR(crtc_state))
> +                       return PTR_ERR(crtc_state);
> +       }
> +
> +       conn_state->crtc = crtc;
> +
> +       if (crtc)
> +               DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
> +                             conn_state, crtc->base.id);
> +       else
> +               DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
> +                             conn_state);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
> +
> +/**
> + * drm_atomic_add_affected_connectors - add connectors for crtc
> + * @state: atomic state
> + * @crtc: DRM crtc
> + *
> + * This function walks the current configuration and adds all connectors
> + * currently using @crtc to the atomic configuration @state. Note that this
> + * function must acquire the connection mutex. This can potentially cause
> + * unneeded seralization if the update is just for the planes on one crtc. Hence
> + * drivers and helpers should only call this when really needed (e.g. when a
> + * full modeset needs to happen due to some change).
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM.
> + */
> +int
> +drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> +                                  struct drm_crtc *crtc)
> +{
> +       struct drm_mode_config *config = &state->dev->mode_config;
> +       struct drm_connector *connector;
> +       struct drm_connector_state *conn_state;
> +       int ret;
> +
> +       ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
> +       if (ret)
> +               return ret;
> +
> +       DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
> +                     crtc->base.id, state);
> +
> +       /*
> +        * Changed connectors are already in @state, so only need to look at the
> +        * current configuration.
> +        */
> +       list_for_each_entry(connector, &config->connector_list, head) {
> +               if (connector->state->crtc != crtc)
> +                       continue;
> +
> +               conn_state = drm_atomic_get_connector_state(state, connector);
> +               if (IS_ERR(conn_state))
> +                       return PTR_ERR(conn_state);
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
> +
> +/**
> + * drm_atomic_connectors_for_crtc - count number of connected outputs
> + * @state: atomic state
> + * @crtc: DRM crtc
> + *
> + * This function counts all connectors which will be connected to @crtc
> + * according to @state. Useful to recompute the enable state for @crtc.
> + */
> +int
> +drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
> +                              struct drm_crtc *crtc)
> +{
> +       int nconnectors = state->dev->mode_config.num_connector;
> +       int i, num_connected_connectors = 0;
> +
> +       for (i = 0; i < nconnectors; i++) {
> +               struct drm_connector_state *conn_state;
> +
> +               conn_state = state->connector_states[i];
> +
> +               if (conn_state && conn_state->crtc == crtc)
> +                       num_connected_connectors++;
> +       }
> +
> +       DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
> +                     state, num_connected_connectors, crtc->base.id);
> +
> +       return num_connected_connectors;
> +}
> +EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
> +
> +/**
> + * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
> + * @state: atomic state
> + *
> + * This function should be used by legacy entry points which don't understand
> + * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
> + *  the slowpath completed.
> + */
> +void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
> +{
> +       int ret;
> +
> +retry:
> +       drm_modeset_backoff(state->acquire_ctx);
> +
> +       ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
> +                              state->acquire_ctx);
> +       if (ret)
> +               goto retry;
> +       ret = drm_modeset_lock_all_crtcs(state->dev,
> +                                        state->acquire_ctx);
> +       if (ret)
> +               goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_legacy_backoff);
> +
> +/**
> + * drm_atomic_check_only - check whether a given config would work
> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_check_only(struct drm_atomic_state *state)
> +{
> +       struct drm_mode_config *config = &state->dev->mode_config;
> +
> +       DRM_DEBUG_KMS("checking %p\n", state);
> +
> +       if (config->funcs->atomic_check)
> +               return config->funcs->atomic_check(state->dev, state);
> +       else
> +               return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_check_only);
> +
> +/**
> + * drm_atomic_commit - commit configuration atomically
> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Also note that on successful execution ownership of @state is transferred
> + * from the caller of this function to the function itself. The caller must not
> + * free or in any other way access @state. If the function fails then the caller
> + * must clean up @state itself.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_commit(struct drm_atomic_state *state)
> +{
> +       struct drm_mode_config *config = &state->dev->mode_config;
> +       int ret;
> +
> +       ret = drm_atomic_check_only(state);
> +       if (ret)
> +               return ret;
> +
> +       DRM_DEBUG_KMS("commiting %p\n", state);
> +
> +       return config->funcs->atomic_commit(state->dev, state, false);
> +}
> +EXPORT_SYMBOL(drm_atomic_commit);
> +
> +/**
> + * drm_atomic_async_commit - atomic&async configuration commit
> + * @state: atomic configuration to check
> + *
> + * Note that this function can return -EDEADLK if the driver needed to acquire
> + * more locks but encountered a deadlock. The caller must then do the usual w/w
> + * backoff dance and restart.
> + *
> + * Also note that on successful execution ownership of @state is transferred
> + * from the caller of this function to the function itself. The caller must not
> + * free or in any other way access @state. If the function fails then the caller
> + * must clean up @state itself.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_atomic_async_commit(struct drm_atomic_state *state)
> +{
> +       struct drm_mode_config *config = &state->dev->mode_config;
> +       int ret;
> +
> +       ret = drm_atomic_check_only(state);
> +       if (ret)
> +               return ret;
> +
> +       DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
> +
> +       return config->funcs->atomic_commit(state->dev, state, true);
> +}
> +EXPORT_SYMBOL(drm_atomic_async_commit);
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> new file mode 100644
> index 000000000000..5bb15f550c42
> --- /dev/null
> +++ b/include/drm/drm_atomic.h
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (C) 2014 Red Hat
> + * Copyright (C) 2014 Intel Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robdclark@gmail.com>
> + * Daniel Vetter <daniel.vetter@ffwll.ch>
> + */
> +
> +#ifndef DRM_ATOMIC_H_
> +#define DRM_ATOMIC_H_
> +
> +struct drm_atomic_state * __must_check
> +drm_atomic_state_alloc(struct drm_device *dev);
> +void drm_atomic_state_clear(struct drm_atomic_state *state);
> +void drm_atomic_state_free(struct drm_atomic_state *state);
> +
> +struct drm_crtc_state * __must_check
> +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> +                         struct drm_crtc *crtc);
> +struct drm_plane_state * __must_check
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +                          struct drm_plane *plane);
> +struct drm_connector_state * __must_check
> +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> +                              struct drm_connector *connector);
> +
> +int __must_check
> +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
> +                             struct drm_crtc *crtc);
> +int __must_check
> +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
> +                                 struct drm_crtc *crtc);
> +int __must_check
> +drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> +                                  struct drm_crtc *crtc);
> +int
> +drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
> +                              struct drm_crtc *crtc);
> +
> +void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
> +
> +int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
> +int __must_check drm_atomic_commit(struct drm_atomic_state *state);
> +int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
> +
> +#endif /* DRM_ATOMIC_H_ */
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 3554868dbf09..07c88ad64234 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -794,6 +794,32 @@ struct drm_bridge {
>  };
>
>  /**
> + * struct struct drm_atomic_state - the global state object for atomic updates
> + * @dev: parent DRM device
> + * @flags: state flags like async update
> + * @planes: pointer to array of plane pointers
> + * @plane_states: pointer to array of plane states pointers
> + * @crtcs: pointer to array of CRTC pointers
> + * @crtc_states: pointer to array of CRTC states pointers
> + * @connectors: pointer to array of connector pointers
> + * @connector_states: pointer to array of connector states pointers
> + * @acquire_ctx: acquire context for this atomic modeset state update
> + */
> +struct drm_atomic_state {
> +       struct drm_device *dev;
> +       uint32_t flags;
> +       struct drm_plane **planes;
> +       struct drm_plane_state **plane_states;
> +       struct drm_crtc **crtcs;
> +       struct drm_crtc_state **crtc_states;
> +       struct drm_connector **connectors;
> +       struct drm_connector_state **connector_states;
> +
> +       struct drm_modeset_acquire_ctx *acquire_ctx;
> +};
> +
> +
> +/**
>   * struct drm_mode_set - new values for a CRTC config change
>   * @fb: framebuffer to use for new config
>   * @crtc: CRTC whose configuration we're about to change
> @@ -824,6 +850,9 @@ struct drm_mode_set {
>   * struct drm_mode_config_funcs - basic driver provided mode setting functions
>   * @fb_create: create a new framebuffer object
>   * @output_poll_changed: function to handle output configuration changes
> + * @atomic_check: check whether a give atomic state update is possible
> + * @atomic_commit: commit an atomic state update previously verified with
> + *     atomic_check()
>   *
>   * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
>   * involve drivers.
> @@ -833,6 +862,12 @@ struct drm_mode_config_funcs {
>                                              struct drm_file *file_priv,
>                                              struct drm_mode_fb_cmd2 *mode_cmd);
>         void (*output_poll_changed)(struct drm_device *dev);
> +
> +       int (*atomic_check)(struct drm_device *dev,
> +                           struct drm_atomic_state *a);
> +       int (*atomic_commit)(struct drm_device *dev,
> +                            struct drm_atomic_state *a,
> +                            bool async);
>  };
>
>  /**
> --
> 2.1.1
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 07/17] drm: Add atomic/plane helpers
  2014-11-04 22:30   ` Sean Paul
@ 2014-11-04 23:16     ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-04 23:16 UTC (permalink / raw)
  To: Sean Paul; +Cc: Intel Graphics Development, DRI Development

On Tue, Nov 4, 2014 at 11:30 PM, Sean Paul <seanpaul@chromium.org> wrote:
>> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
>> index 89829ae58e97..ea0ef43b19e1 100644
>> --- a/Documentation/DocBook/drm.tmpl
>> +++ b/Documentation/DocBook/drm.tmpl
>> @@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
>>  !Edrivers/gpu/drm/drm_modes.c
>>      </sect2>
>>      <sect2>
>> +      <title>Atomic Mode Setting Function Reference</title>
>> +!Edrivers/gpu/drm/drm_atomic.c
>> +    </sect2>
>> +    <sect2>
>
> This change should probably be in the previous patch.

Yeah, fixed locally. Thanks for the review so far.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm/atomic-helper: implement ->page_flip
  2014-11-04 22:09   ` [PATCH] " Daniel Vetter
@ 2014-11-05 11:35     ` Daniel Thompson
  2014-11-05 13:46     ` Daniel Vetter
  1 sibling, 0 replies; 77+ messages in thread
From: Daniel Thompson @ 2014-11-05 11:35 UTC (permalink / raw)
  To: Daniel Vetter, DRI Development; +Cc: Intel Graphics Development

On 04/11/14 22:09, Daniel Vetter wrote:
> Currently there is no way to implement async flips using atomic, that
> essentially requires us to be able to cancel pending requests
> mid-flight.
> 
> To be able to do that (and I guess we want this since vblank synced
> updates whic opportunistically cancel still pending updates seem to be
> wanted) we'd need to add a mandatory cancellation mode. Depending upon
> the exact semantics we decide upon that could mean that userspace will
> not get completion events, or will get them all stacked up.
> 
> So reject async updates for now. Also async updates usually means not
> vblank synced at all, and I guess for drivers which want to support
> this they should simply add a special pageflip handler (since usually
> you need a special flip cmd to achieve this). That kind of async flip
> is pretty much exclusively just used for games and benchmarks where
> dropping just one frame means you'll get a headshot or something bad
> like that ... And so slight amounts of tearing is acceptable.
> 
> v2: Fixup kerneldoc, reported by Paulo.
> 
> v3: Use the set_crtc_for_plane function to assign the crtc, since
> otherwise the book-keeping is off.
> 
> v4: Update crtc->primary->fb since ->page_flip is the only driver
> callback where the core won't do this itself. We might want to fix
> this inconsistency eventually.
> 
> v5: Use set_crtc_for_connector as suggested by Sean.
> 
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 92 +++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic_helper.h     |  5 ++
>  2 files changed, 97 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 790edc18b2cb..36ccc42d43db 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1633,3 +1633,95 @@ backoff:
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
> +
> +/**
> + * drm_atomic_helper_page_flip - execute a legacy page flip
> + * @crtc: DRM crtc
> + * @fb: DRM framebuffer
> + * @event: optional DRM event to signal upon completion
> + * @flags: flip flags for non-vblank sync'ed updates
> + *
> + * Provides a default page flip implementation using the atomic driver interface.
> + *
> + * Note that for now so called async page flips (i.e. updates which are not
> + * synchronized to vblank) are not supported, since the atomic interfaces have
> + * no provisions for this yet.
> + *
> + * Returns:
> + * Returns 0 on success, negative errno numbers on failure.
> + */
> +int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
> +				struct drm_framebuffer *fb,
> +				struct drm_pending_vblank_event *event,
> +				uint32_t flags)
> +{
> +	struct drm_plane *plane = crtc->primary;
> +	struct drm_atomic_state *state;
> +	struct drm_plane_state *plane_state;
> +	struct drm_crtc_state *crtc_state;
> +	int ret = 0;
> +
> +	if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
> +		return -EINVAL;
> +
> +	state = drm_atomic_state_alloc(plane->dev);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> +retry:
> +	crtc_state = drm_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state)) {
> +		ret = PTR_ERR(crtc_state);
> +		if (ret == -EDEADLK)
> +			goto backoff;
> +		else
> +			goto fail;
> +	}
> +	crtc_state->event = event;
> +
> +	plane_state = drm_atomic_get_plane_state(state, plane);
> +	if (IS_ERR(plane_state)) {
> +		ret = PTR_ERR(plane_state);
> +		if (ret == -EDEADLK)
> +			goto backoff;
> +		else
> +			goto fail;
> +	}
> +
> +	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
> +	if (ret == -EDEADLK)
> +		goto backoff;

The kerneldoc for this function states that it can return -ENOMEM too
and, even if it didn't, this approach to error handling is potentially
fragile as the kernel changes.


> +	plane_state->fb = fb;
> +
> +	ret = drm_atomic_async_commit(state);
> +	if (ret == -EDEADLK)
> +		goto backoff;

A fussy point but this would be easier to read if it followed the same
pattern as the above error checks with a "goto fail". The the success
path below can be outdented and made more obvious.


> +
> +	/* Driver takes ownership of state on successful async commit. */
> +	if (ret == 0) {
> +		/* TODO: ->page_flip is the only driver callback where the core
> +		 * doesn't update plane->fb. For now patch it up here. */
> +		plane->fb = plane->state->fb;
> +
> +		return 0;
> +	}
> +
> +fail:
> +	drm_atomic_state_free(state);
> +
> +	return ret;
> +backoff:
> +	drm_atomic_legacy_backoff(state);
> +	drm_atomic_state_clear(state);
> +
> +	/*
> +	 * Someone might have exchanged the framebuffer while we dropped locks
> +	 * in the backoff code. We need to fix up the fb refcount tracking the
> +	 * core does for us.
> +	 */
> +	plane->old_fb = plane->fb;
> +
> +	goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_page_flip);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 8cd6fe7a48e5..28a2f3a815fd 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
>  int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
>  					struct drm_property *property,
>  					uint64_t val);
> +int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
> +				struct drm_framebuffer *fb,
> +				struct drm_pending_vblank_event *event,
> +				uint32_t flags);
> +
>  
>  #endif /* DRM_ATOMIC_HELPER_H_ */
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm: Global atomic state handling
  2014-11-04 22:07     ` Daniel Vetter
  2014-11-04 22:32       ` Sean Paul
@ 2014-11-05 13:06       ` Ander Conselvan de Oliveira
  2014-11-05 13:45       ` Daniel Vetter
  2 siblings, 0 replies; 77+ messages in thread
From: Ander Conselvan de Oliveira @ 2014-11-05 13:06 UTC (permalink / raw)
  To: Daniel Vetter, DRI Development; +Cc: Intel Graphics Development, Fengguang Wu

On 11/05/2014 12:07 AM, Daniel Vetter wrote:
>   /**
> + * struct struct drm_atomic_state - the global state object for atomic updates
> + * @dev: parent DRM device
> + * @flags: state flags like async update
> + * @planes: pointer to array of plane pointers
> + * @plane_states: pointer to array of plane states pointers
> + * @crtcs: pointer to array of CRTC pointers
> + * @crtc_states: pointer to array of CRTC states pointers
> + * @connectors: pointer to array of connector pointers
> + * @connector_states: pointer to array of connector states pointers
> + * @acquire_ctx: acquire context for this atomic modeset state update
> + */
> +struct drm_atomic_state {
> +       struct drm_device *dev;
> +       uint32_t flags;
> +       struct drm_plane **planes;
> +       struct drm_plane_state **plane_states;
> +       struct drm_crtc **crtcs;
> +       struct drm_crtc_state **crtc_states;
> +       struct drm_connector **connectors;
> +       struct drm_connector_state **connector_states;
> +
> +       struct drm_modeset_acquire_ctx *acquire_ctx;
> +};


The lines above are indented with spaces instead of tabs.


Ander
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm: Global atomic state handling
  2014-11-04 22:07     ` Daniel Vetter
  2014-11-04 22:32       ` Sean Paul
  2014-11-05 13:06       ` Ander Conselvan de Oliveira
@ 2014-11-05 13:45       ` Daniel Vetter
  2014-11-05 14:22         ` Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 13:45 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Thompson, Daniel Vetter, Intel Graphics Development, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

v13: Review from Sean:
- kerneldoc spelling fixes
- Don't overallocate states->planes.
- Handle NULL crtc in set_crtc_for_connector.

v14: Sprinkle __must_check over all functions which do wait/wound
locking to make sure callers don't forget this. Since I have ;-)

v15: Be more explicit in the kerneldoc when functions can return
-EDEADLK what to do. And that every other -errno is fatal.

Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |   4 +
 drivers/gpu/drm/Makefile       |   2 +-
 drivers/gpu/drm/drm_atomic.c   | 600 +++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h       |  65 +++++
 include/drm/drm_crtc.h         |  35 +++
 5 files changed, 705 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index f83d3b6ea4e5..748513b34025 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
 !Edrivers/gpu/drm/drm_modes.c
     </sect2>
     <sect2>
+      <title>Atomic Mode Setting Function Reference</title>
+!Edrivers/gpu/drm/drm_atomic.c
+    </sect2>
+    <sect2>
       <title>Frame Buffer Creation</title>
       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
 				     struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9292a761ea6d..c5e37dc459ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..ad15a88c0f74
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->planes), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This function returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This function returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This function returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	conn_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+			      conn_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
+			      conn_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async configuration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..5bb15f550c42
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state * __must_check
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state * __must_check
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state * __must_check
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state * __must_check
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int __must_check
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc);
+int __must_check
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc);
+int __must_check
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
+int __must_check drm_atomic_commit(struct drm_atomic_state *state);
+int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3554868dbf09..07c88ad64234 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -794,6 +794,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+       struct drm_device *dev;
+       uint32_t flags;
+       struct drm_plane **planes;
+       struct drm_plane_state **plane_states;
+       struct drm_crtc **crtcs;
+       struct drm_crtc_state **crtc_states;
+       struct drm_connector **connectors;
+       struct drm_connector_state **connector_states;
+
+       struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -824,6 +850,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -833,6 +862,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-04 22:08   ` [PATCH] " Daniel Vetter
@ 2014-11-05 13:46     ` Daniel Vetter
  2014-11-05 19:48       ` Sean Paul
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 13:46 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Well, except page_flip since that requires async commit, which isn't
there yet.

For the functions which changes planes there's a bit of trickery
involved to keep the fb refcounting working. But otherwise fairly
straight-forward atomic updates.

The property setting functions are still a bit incomplete. Once we
have generic properties (e.g. rotation, but also all the properties
needed by the atomic ioctl) we need to filter those out and parse them
in the helper. Preferrably with the same function as used by the real
atomic ioctl implementation.

v2: Fixup kerneldoc, reported by Paulo.

v3: Add missing EXPORT_SYMBOL.

v4: We need to look at the crtc of the modeset, not some random
leftover one from a previous loop when udpating the connector->crtc
routing. Also push some local variables into inner loops to avoid
these kinds of bugs.

v5: Adjust semantics - drivers now own the atomic state upon
successfully synchronous commit.

v6: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v7:
- Improve comments.
- Filter out the crtc of the ->set_config call when recomputing
  crtc_state->enabled: We should compute the same state, but not doing
  so will give us a good chance to catch bugs and inconsistencies -
  the atomic helper's atomic_check function re-validates this again.
- Fix the set_config implementation logic when disabling the crtc: We
  still need to update the output routing to disable all the
  connectors properly in the state. Caught by the atomic_check
  functions, so at least that part worked ;-) Also add some WARN_ONs
  to ensure ->set_config preconditions all apply.

v8: Fixup an embarrassing h/vdisplay mixup.

v9: Shuffled bad squash to the right patch, spotted by Daniel

v10: Use set_crtc_for_connector as suggested by Sean.

v11: Daniel Thompson noticed that my error handling is inconsistent
and that in a few cases I didn't handle fatal errors (i.e. not
-EDEADLK). Fix this by consolidate the ww mutex backoff handling
into one check in the fail: block and flatten the error control
flow everywhere else.

Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 504 +++++++++++++++++++++++++++++++++++-
 include/drm/drm_atomic_helper.h     |  21 ++
 2 files changed, 524 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 887e1971c915..b84581f8c8fc 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -86,6 +86,7 @@ steal_encoder(struct drm_atomic_state *state,
 	struct drm_crtc_state *crtc_state;
 	struct drm_connector *connector;
 	struct drm_connector_state *connector_state;
+	int ret;
 
 	/*
 	 * We can only steal an encoder coming from a connector, which means we
@@ -116,7 +117,9 @@ steal_encoder(struct drm_atomic_state *state,
 		if (IS_ERR(connector_state))
 			return PTR_ERR(connector_state);
 
-		connector_state->crtc = NULL;
+		ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
+		if (ret)
+			return ret;
 		connector_state->best_encoder = NULL;
 	}
 
@@ -1045,3 +1048,502 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
+
+/**
+ * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	if (ret != 0)
+		goto fail;
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_update_plane);
+
+/**
+ * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic
+ * @plane: plane to disable
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_helper_disable_plane(struct drm_plane *plane)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc);
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+	if (ret != 0)
+		goto fail;
+	plane_state->fb = NULL;
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_h = 0;
+	plane_state->crtc_w = 0;
+	plane_state->src_x = 0;
+	plane_state->src_y = 0;
+	plane_state->src_h = 0;
+	plane_state->src_w = 0;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_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_connector_state *conn_state;
+	int nconnectors = state->dev->mode_config.num_connector;
+	int ncrtcs = state->dev->mode_config.num_crtc;
+	int ret, i, j;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	/* First grab all affected connector/crtc states. */
+	for (i = 0; i < set->num_connectors; i++) {
+		conn_state = drm_atomic_get_connector_state(state,
+							    set->connectors[i]);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		ret = drm_atomic_add_affected_connectors(state, crtc);
+		if (ret)
+			return ret;
+	}
+
+	/* Then recompute connector->crtc links and crtc enabling state. */
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector *connector;
+
+		connector = state->connectors[i];
+		conn_state = state->connector_states[i];
+
+		if (!connector)
+			continue;
+
+		if (conn_state->crtc == set->crtc) {
+			ret = drm_atomic_set_crtc_for_connector(conn_state,
+								NULL);
+			if (ret)
+				return ret;
+		}
+
+		for (j = 0; j < set->num_connectors; j++) {
+			if (set->connectors[j] == connector) {
+				ret = drm_atomic_set_crtc_for_connector(conn_state,
+									set->crtc);
+				if (ret)
+					return ret;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+		struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+		if (!crtc && crtc != set->crtc)
+			continue;
+
+		crtc_state->enable =
+			drm_atomic_connectors_for_crtc(state, crtc);
+	}
+
+	return 0;
+}
+
+/**
+ * drm_atomic_helper_set_config - set a new config from userspace
+ * @set: mode set configuration
+ *
+ * Provides a default crtc set_config handler using the atomic driver interface.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_set_config(struct drm_mode_set *set)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc *crtc = set->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane_state *primary_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto fail;
+	}
+
+	if (!set->mode) {
+		WARN_ON(set->fb);
+		WARN_ON(set->num_connectors);
+
+		crtc_state->enable = false;
+		goto commit;
+	}
+
+	WARN_ON(!set->fb);
+	WARN_ON(!set->num_connectors);
+
+	crtc_state->enable = true;
+	drm_mode_copy(&crtc_state->mode, set->mode);
+
+	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+	if (IS_ERR(primary_state)) {
+		ret = PTR_ERR(primary_state);
+		goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
+	if (ret != 0)
+		goto fail;
+	primary_state->fb = set->fb;
+	primary_state->crtc_x = 0;
+	primary_state->crtc_y = 0;
+	primary_state->crtc_h = set->mode->vdisplay;
+	primary_state->crtc_w = set->mode->hdisplay;
+	primary_state->src_x = set->x << 16;
+	primary_state->src_y = set->y << 16;
+	primary_state->src_h = set->mode->vdisplay << 16;
+	primary_state->src_w = set->mode->hdisplay << 16;
+
+commit:
+	ret = update_output_state(state, set);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	crtc->primary->old_fb = crtc->primary->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_set_config);
+
+/**
+ * drm_atomic_helper_crtc_set_property - helper for crtc prorties
+ * @crtc: DRM crtc
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto fail;
+	}
+
+	ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
+					       property, val);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
+
+/**
+ * drm_atomic_helper_plane_set_property - helper for plane prorties
+ * @plane: DRM plane
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disable handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = plane->dev->mode_config.acquire_ctx;
+retry:
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		goto fail;
+	}
+
+	ret = plane->funcs->atomic_set_property(plane, plane_state,
+					       property, val);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+/**
+ * drm_atomic_helper_connector_set_property - helper for connector prorties
+ * @connector: DRM connector
+ * @property: DRM property
+ * @val: value of property
+ *
+ * Provides a default plane disablle handler using the atomic driver interface.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int
+drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+				    struct drm_property *property,
+				    uint64_t val)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector_state *connector_state;
+	int ret = 0;
+
+	state = drm_atomic_state_alloc(connector->dev);
+	if (!state)
+		return -ENOMEM;
+
+	/* ->set_property is always called with all locks held. */
+	state->acquire_ctx = connector->dev->mode_config.acquire_ctx;
+retry:
+	connector_state = drm_atomic_get_connector_state(state, connector);
+	if (IS_ERR(connector_state)) {
+		ret = PTR_ERR(connector_state);
+		goto fail;
+	}
+
+	ret = connector->funcs->atomic_set_property(connector, connector_state,
+					       property, val);
+	if (ret)
+		goto fail;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 9781ce739e10..8cd6fe7a48e5 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -49,4 +49,25 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
 void drm_atomic_helper_swap_state(struct drm_device *dev,
 				  struct drm_atomic_state *state);
 
+/* implementations for legacy interfaces */
+int drm_atomic_helper_update_plane(struct drm_plane *plane,
+				   struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int crtc_x, int crtc_y,
+				   unsigned int crtc_w, unsigned int crtc_h,
+				   uint32_t src_x, uint32_t src_y,
+				   uint32_t src_w, uint32_t src_h);
+int drm_atomic_helper_disable_plane(struct drm_plane *plane);
+int drm_atomic_helper_set_config(struct drm_mode_set *set);
+
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
+					struct drm_property *property,
+					uint64_t val);
+int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
+					struct drm_property *property,
+					uint64_t val);
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* [PATCH] drm/atomic-helper: implement ->page_flip
  2014-11-04 22:09   ` [PATCH] " Daniel Vetter
  2014-11-05 11:35     ` Daniel Thompson
@ 2014-11-05 13:46     ` Daniel Vetter
  1 sibling, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 13:46 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Currently there is no way to implement async flips using atomic, that
essentially requires us to be able to cancel pending requests
mid-flight.

To be able to do that (and I guess we want this since vblank synced
updates whic opportunistically cancel still pending updates seem to be
wanted) we'd need to add a mandatory cancellation mode. Depending upon
the exact semantics we decide upon that could mean that userspace will
not get completion events, or will get them all stacked up.

So reject async updates for now. Also async updates usually means not
vblank synced at all, and I guess for drivers which want to support
this they should simply add a special pageflip handler (since usually
you need a special flip cmd to achieve this). That kind of async flip
is pretty much exclusively just used for games and benchmarks where
dropping just one frame means you'll get a headshot or something bad
like that ... And so slight amounts of tearing is acceptable.

v2: Fixup kerneldoc, reported by Paulo.

v3: Use the set_crtc_for_plane function to assign the crtc, since
otherwise the book-keeping is off.

v4: Update crtc->primary->fb since ->page_flip is the only driver
callback where the core won't do this itself. We might want to fix
this inconsistency eventually.

v5: Use set_crtc_for_connector as suggested by Sean.

v6: Daniel Thompson noticed that my error handling is inconsistent
and that in a few cases I didn't handle fatal errors (i.e. not
-EDEADLK). Fix this by consolidate the ww mutex backoff handling
into one check in the fail: block and flatten the error control
flow everywhere else.

Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 86 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  5 +++
 2 files changed, 91 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index c7d1554b7ce1..6b490571c803 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1608,3 +1608,89 @@ backoff:
 	goto retry;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
+
+/**
+ * drm_atomic_helper_page_flip - execute a legacy page flip
+ * @crtc: DRM crtc
+ * @fb: DRM framebuffer
+ * @event: optional DRM event to signal upon completion
+ * @flags: flip flags for non-vblank sync'ed updates
+ *
+ * Provides a default page flip implementation using the atomic driver interface.
+ *
+ * Note that for now so called async page flips (i.e. updates which are not
+ * synchronized to vblank) are not supported, since the atomic interfaces have
+ * no provisions for this yet.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags)
+{
+	struct drm_plane *plane = crtc->primary;
+	struct drm_atomic_state *state;
+	struct drm_plane_state *plane_state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0;
+
+	if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+		return -EINVAL;
+
+	state = drm_atomic_state_alloc(plane->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto fail;
+	}
+	crtc_state->event = event;
+
+	plane_state = drm_atomic_get_plane_state(state, plane);
+	if (IS_ERR(plane_state)) {
+		ret = PTR_ERR(plane_state);
+		goto fail;
+	}
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+	if (ret != 0)
+		goto fail;
+	plane_state->fb = fb;
+
+	ret = drm_atomic_async_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* TODO: ->page_flip is the only driver callback where the core
+	 * doesn't update plane->fb. For now patch it up here. */
+	plane->fb = plane->state->fb;
+
+	/* Driver takes ownership of state on successful async commit. */
+	return 0;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	return ret;
+backoff:
+	drm_atomic_legacy_backoff(state);
+	drm_atomic_state_clear(state);
+
+	/*
+	 * Someone might have exchanged the framebuffer while we dropped locks
+	 * in the backoff code. We need to fix up the fb refcount tracking the
+	 * core does for us.
+	 */
+	plane->old_fb = plane->fb;
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_page_flip);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 8cd6fe7a48e5..28a2f3a815fd 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
 int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
 					struct drm_property *property,
 					uint64_t val);
+int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				struct drm_pending_vblank_event *event,
+				uint32_t flags);
+
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* [PATCH] drm: Global atomic state handling
  2014-11-05 13:45       ` Daniel Vetter
@ 2014-11-05 14:22         ` Daniel Vetter
  2014-11-05 17:06           ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 14:22 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

v13: Review from Sean:
- kerneldoc spelling fixes
- Don't overallocate states->planes.
- Handle NULL crtc in set_crtc_for_connector.

v14: Sprinkle __must_check over all functions which do wait/wound
locking to make sure callers don't forget this. Since I have ;-)

v15: Be more explicit in the kerneldoc when functions can return
-EDEADLK what to do. And that every other -errno is fatal.

v20: Indent with tabs instead of space, spotted by Ander.

Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |   4 +
 drivers/gpu/drm/Makefile       |   2 +-
 drivers/gpu/drm/drm_atomic.c   | 600 +++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h       |  65 +++++
 include/drm/drm_crtc.h         |  35 +++
 5 files changed, 705 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index f83d3b6ea4e5..748513b34025 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
 !Edrivers/gpu/drm/drm_modes.c
     </sect2>
     <sect2>
+      <title>Atomic Mode Setting Function Reference</title>
+!Edrivers/gpu/drm/drm_atomic.c
+    </sect2>
+    <sect2>
       <title>Frame Buffer Creation</title>
       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
 				     struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9292a761ea6d..c5e37dc459ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..ad15a88c0f74
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->planes), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This function returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This function returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This function returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	conn_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+			      conn_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
+			      conn_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async configuration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..5bb15f550c42
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state * __must_check
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state * __must_check
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state * __must_check
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state * __must_check
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int __must_check
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc);
+int __must_check
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc);
+int __must_check
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
+int __must_check drm_atomic_commit(struct drm_atomic_state *state);
+int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3554868dbf09..b172817e10c7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -794,6 +794,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+	struct drm_device *dev;
+	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **plane_states;
+	struct drm_crtc **crtcs;
+	struct drm_crtc_state **crtc_states;
+	struct drm_connector **connectors;
+	struct drm_connector_state **connector_states;
+
+	struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -824,6 +850,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -833,6 +862,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

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

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

* Re: [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc
  2014-11-02 13:19 ` [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
@ 2014-11-05 16:18   ` Thierry Reding
  1 sibling, 0 replies; 77+ messages in thread
From: Thierry Reding @ 2014-11-05 16:18 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development


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

On Sun, Nov 02, 2014 at 02:19:17PM +0100, Daniel Vetter wrote:
> I've forgotten to do this in:
> 
> commit cb597bb3a2fbfc871cc1c703fb330d247bd21394
> Author: Daniel Vetter <daniel.vetter@ffwll.ch>
> Date:   Sun Jul 27 19:09:33 2014 +0200
> 
>     drm: trylock modest locking for fbdev panics
> 
> Oops, fix this asap.
> 
> In my defense kerneldoc is really awful and there's no way it can pick
> up structured comments per struct member. Which means we need both
> since people won't scroll up even a few lines.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
>  include/drm/drm_modeset_lock.h | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Thierry Reding <treding@nvidia.com>

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 05/17] drm: Add atomic driver interface definitions for objects
  2014-11-02 13:19 ` [PATCH 05/17] drm: Add atomic driver interface definitions for objects Daniel Vetter
  2014-11-04 20:31   ` Sean Paul
@ 2014-11-05 16:26   ` Thierry Reding
  2014-11-05 17:04     ` Daniel Vetter
  1 sibling, 1 reply; 77+ messages in thread
From: Thierry Reding @ 2014-11-05 16:26 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development


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

On Sun, Nov 02, 2014 at 02:19:18PM +0100, Daniel Vetter wrote:
[...]
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index a68e02be7e37..9847009ad451 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -224,6 +224,25 @@ struct drm_encoder;
>  struct drm_pending_vblank_event;
>  struct drm_plane;
>  struct drm_bridge;
> +struct drm_atomic_state;
> +
> +/**
> + * struct drm_crtc_state - mutable crtc state
> + * @enable: whether the CRTC should be enabled, gates all other state

You use a mix of "crtc" and "CRTC" here. Since it's an abbreviation it
should really be "CRTC" consistently. The commit message also suffers
from this.

> + * @mode: current mode timings
> + * @event: optional pointer to a DRM event to signal upon completion of the
> + * 	state update
> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_crtc_state {
> +	bool enable        : 1;

I thought there had been a recent thread about bitfields being
discouraged.

> @@ -288,6 +310,15 @@ struct drm_crtc_funcs {
>  
>  	int (*set_property)(struct drm_crtc *crtc,
>  			    struct drm_property *property, uint64_t val);
> +
> +	/* atomic update handling */
> +	struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
> +	void (*atomic_destroy_state)(struct drm_crtc *crtc,
> +				     struct drm_crtc_state *cstate);

Why is the second parameter named "cstate"? Other functions use simply
"state".

> +/**
> + * struct drm_connector_state - mutable connector state
> + * @crtc: crtc to connect connector to, NULL if disabled

s/crtc/CRTC/

> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_connector_state {
> +	struct drm_crtc *crtc;
> +
> +	struct drm_atomic_state *state;
> +};
>  
>  /**
>   * struct drm_connector_funcs - control connectors on a given device
> @@ -393,6 +437,10 @@ struct drm_crtc {
>   * @set_property: property for this connector may need an update
>   * @destroy: make object go away
>   * @force: notify the driver that the connector is forced on
> + * @atomic_duplicate_state: duplicate the atomic state for this connector
> + * @atomic_destroy_state: destroy an atomic state for this connector
> + * @atomic_set_property: set a property on an atomic state for this connector
> + *

The last line here seems gratuituous.

> +/**
> + * struct drm_plane_state - mutable plane state
> + * @crtc: currently bound CRTC, NULL if disabled
> + * @fb: currently bound fb

Nit: For consistency with the spelling for CRTC this should be FB.

> + * @crtc_x: left position of visible portion of plane on crtc
> + * @crtc_y: upper position of visible portion of plane on crtc
> + * @crtc_w: width of visible portion of plane on crtc
> + * @crtc_h: height of visible portion of plane on crtc
> + * @src_x: left position of visible portion of plane within
> + *	plane (in 16.16)
> + * @src_y: upper position of visible portion of plane within
> + *	plane (in 16.16)
> + * @src_w: width of visible portion of plane (in 16.16)
> + * @src_h: height of visible portion of plane (in 16.16)
> + * @state: backpointer to global drm_atomic_state
> + */
> +struct drm_plane_state {
> +	struct drm_crtc *crtc;
> +	struct drm_framebuffer *fb;
> +
> +	/* Signed dest location allows it to be partially off screen */
> +	int32_t crtc_x, crtc_y;
> +	uint32_t crtc_w, crtc_h;

Should these perhaps be unsized types? For the same reasons you argued
the other day.

> +
> +	/* Source values are 16.16 fixed point */
> +	uint32_t src_x, src_y;
> +	uint32_t src_h, src_w;

Do we really use the 16.16 fixed point format for these? Maybe now would
be a good time to get rid of that if we don't need it. If they're not a
16.16 fixed point format they could also be unsized.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

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

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

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

* Re: [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers
  2014-11-02 13:19 ` [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers Daniel Vetter
@ 2014-11-05 16:45   ` Sean Paul
  2014-11-05 16:51     ` Daniel Vetter
  2014-11-05 16:59   ` [PATCH] " Daniel Vetter
  1 sibling, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-05 16:45 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:21PM +0100, Daniel Vetter wrote:
> Converting a driver to the atomic interface can be a daunting
> undertaking. One of the prerequisites is to have full universal planes
> support.
>
> To make that transition a bit easier this pathc provides plane helpers

s/pathc/patch/

> which use the new atomic helper callbacks just only for the plane
> changes. This way the plane update functionality can be tested without
> being forced to convert everything at once.
>
> Of course a real atomic update capable driver will implement the
> all plane properties through the atomic interface, so these helpers
> are mostly transitional. But they can be used to enable proper
> universal plane support, especially once the crtc helpers have also
> been adapted.
>
> v2: Use ->atomic_duplicate_state if available.
>
> v3: Don't forget to call ->atomic_destroy_state if available.
>
> v4: Fixup kerneldoc, reported by Paulo.
>
> v5: Extract a common plane_commit helper and fix some bugs in the
> plane_state setup of the plane_disable implementation.
>
> v6: Fix issues with the cleanup of the old fb. Since transitional
> helpers can be mixed we need to assume that the old fb has been set up
> by a legacy path (e.g. set_config or page_flip when the primary plane
> is converted to use these functions already). Hence pass an additional
> old_fb parameter to plane_commit to do that cleanup work correctly.
>
> v7:
> - Fix spurious WARNING (crtc helpers really love to disable stuff
>   harder) and fix array index bonghits.
> - Correctly handle the lack of plane->state object, necessary for
>   transitional use.
> - Don't indicate failure if drm_vblank_get doesn't work - that's
>   expected when the pipe is in dpms off mode.
>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Just a few nits to prove that I read the whole thing ;-).

Reviewed-by: Sean Paul <seanpaul@chromium.org>


> ---
>  drivers/gpu/drm/drm_plane_helper.c | 172 ++++++++++++++++++++++++++++++++++++-
>  include/drm/drm_plane_helper.h     |   8 ++
>  2 files changed, 179 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> index 827ec1a3040b..45aa8c98e3fb 100644
> --- a/drivers/gpu/drm/drm_plane_helper.c
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -27,7 +27,7 @@
>  #include <drm/drmP.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_rect.h>
> -#include <drm/drm_plane_helper.h>
> +#include <drm/drm_crtc_helper.h>
>
>  #define SUBPIXEL_MASK 0xffff
>
> @@ -369,3 +369,173 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>   return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
>  }
>  EXPORT_SYMBOL(drm_crtc_init);
> +
> +static int
> +plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
> +     struct drm_framebuffer *old_fb)
> +{
> + struct drm_plane_helper_funcs *plane_funcs;
> + struct drm_crtc *crtc[2];
> + struct drm_crtc_helper_funcs *crtc_funcs[2];
> + int i, ret = 0;
> +
> + plane_funcs = plane->helper_private;
> +
> + /* Since this is a transitional helper we can't assume that plane->state
> + * is always valid. Hence we need to use plane->crtc instead of
> + * plane->state->crtc as the old crtc. */
> + crtc[0] = plane->crtc;
> + crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
> +
> + for (i = 0; i < 2; i++)
> + crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
> +
> + if (plane_funcs->atomic_check) {
> + ret = plane_funcs->atomic_check(plane, plane_state);
> + if (ret)
> + goto fail;
> + }
> +
> + if (plane_funcs->prepare_fb && plane_state->fb) {
> + ret = plane_funcs->prepare_fb(plane, plane_state->fb);
> + if (ret)
> + goto fail;
> + }
> +
> + /* Point of no return, commit sw state. */
> + swap(plane->state, plane_state);
> +
> + for (i = 0; i < 2; i++) {
> + if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
> + crtc_funcs[i]->atomic_begin(crtc[i]);
> + }
> +
> + plane_funcs->atomic_update(plane);
> +
> + for (i = 0; i < 2; i++) {
> + if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
> + crtc_funcs[i]->atomic_flush(crtc[i]);
> + }
> +
> + for (i = 0; i < 2; i++) {
> + if (!crtc[i])
> + continue;
> +
> + /* There's no other way to figure out whether the crtc is running. */
> + ret = drm_crtc_vblank_get(crtc[i]);
> + if (ret == 0) {
> + drm_crtc_wait_one_vblank(crtc[i]);
> + drm_crtc_vblank_put(crtc[i]);
> + }

This will be good motivation for driver writers to convert to universal
planes!

> +
> + ret = 0;
> + }
> +
> + if (plane_funcs->cleanup_fb && old_fb)
> + plane_funcs->cleanup_fb(plane, old_fb);
> +fail:

minor nit: Might be better to rename this "out", so it's clear that it's
intended to run even in the successful case.

> + if (plane_state) {
> + if (plane->funcs->atomic_destroy_state)
> + plane->funcs->atomic_destroy_state(plane, plane_state);
> + else
> + kfree(plane_state);
> + }
> +
> + return ret;
> +}
> +
> +/**
> + * drm_plane_helper_update() - Helper for primary plane update
> + * @plane: plane object to update
> + * @crtc: owning CRTC of owning plane
> + * @fb: framebuffer to flip onto plane
> + * @crtc_x: x offset of primary plane on crtc
> + * @crtc_y: y offset of primary plane on crtc
> + * @crtc_w: width of primary plane rectangle on crtc
> + * @crtc_h: height of primary plane rectangle on crtc
> + * @src_x: x offset of @fb for panning
> + * @src_y: y offset of @fb for panning
> + * @src_w: width of source rectangle in @fb
> + * @src_h: height of source rectangle in @fb
> + *
> + * Provides a default plane update handler using the atomic plane update
> + * functions. It is fully left to the driver to check plane constraints and
> + * handle corner-cases like a fully occluded or otherwise invisible plane.
> + *
> + * This is useful for piecewise transitioning of a driver to the atomic helpers.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
> +    struct drm_framebuffer *fb,
> +    int crtc_x, int crtc_y,
> +    unsigned int crtc_w, unsigned int crtc_h,
> +    uint32_t src_x, uint32_t src_y,
> +    uint32_t src_w, uint32_t src_h)
> +{
> + struct drm_plane_state *plane_state;
> +
> + if (plane->funcs->atomic_duplicate_state)
> + plane_state = plane->funcs->atomic_duplicate_state(plane);
> + else if (plane->state)
> + plane_state = kmemdup(plane->state, sizeof(*plane_state),
> +      GFP_KERNEL);
> + else
> + plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
> + if (!plane_state)
> + return -ENOMEM;
> +
> + plane_state->crtc = crtc;
> + plane_state->fb = fb;
> + plane_state->crtc_x = crtc_x;
> + plane_state->crtc_y = crtc_y;
> + plane_state->crtc_h = crtc_h;
> + plane_state->crtc_w = crtc_w;
> + plane_state->src_x = src_x;
> + plane_state->src_y = src_y;
> + plane_state->src_h = src_h;
> + plane_state->src_w = src_w;
> +
> + return plane_commit(plane, plane_state, plane->fb);
> +}
> +EXPORT_SYMBOL(drm_plane_helper_update);
> +
> +/**
> + * drm_plane_helper_disable() - Helper for primary plane disable
> + * @plane: plane to disable
> + *
> + * Provides a default plane disable handler using the atomic plane update
> + * functions. It is fully left to the driver to check plane constraints and
> + * handle corner-cases like a fully occluded or otherwise invisible plane.
> + *
> + * This is useful for piecewise transitioning of a driver to the atomic helpers.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_plane_helper_disable(struct drm_plane *plane)
> +{
> + struct drm_plane_state *plane_state;
> +
> + /* crtc helpers love to call disable functions for already disabled hw
> + * functions. So cope with that. */
> + if (!plane->crtc)
> + return 0;
> +
> + if (plane->funcs->atomic_duplicate_state)
> + plane_state = plane->funcs->atomic_duplicate_state(plane);
> + else if (plane->state)
> + plane_state = kmemdup(plane->state, sizeof(*plane_state),
> +      GFP_KERNEL);
> + else
> + plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
> + if (!plane_state)
> + return -ENOMEM;
> +
> + plane_state->crtc = NULL;
> + plane_state->fb = NULL;
> +
> + return plane_commit(plane, plane_state, plane->fb);
> +}
> +EXPORT_SYMBOL(drm_plane_helper_disable);
> diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> index c2146a7d91fb..8a0709704af0 100644
> --- a/include/drm/drm_plane_helper.h
> +++ b/include/drm/drm_plane_helper.h
> @@ -94,4 +94,12 @@ extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
>   int num_formats);
>
>
> +int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
> +    struct drm_framebuffer *fb,
> +    int crtc_x, int crtc_y,
> +    unsigned int crtc_w, unsigned int crtc_h,
> +    uint32_t src_x, uint32_t src_y,
> +    uint32_t src_w, uint32_t src_h);
> +int drm_plane_helper_disable(struct drm_plane *plane);
> +
>  #endif
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers
  2014-11-05 16:45   ` Sean Paul
@ 2014-11-05 16:51     ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 16:51 UTC (permalink / raw)
  To: Sean Paul; +Cc: Intel Graphics Development, DRI Development

On Wed, Nov 5, 2014 at 5:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
>> + /* There's no other way to figure out whether the crtc is running. */
>> + ret = drm_crtc_vblank_get(crtc[i]);
>> + if (ret == 0) {
>> + drm_crtc_wait_one_vblank(crtc[i]);
>> + drm_crtc_vblank_put(crtc[i]);
>> + }
>
> This will be good motivation for driver writers to convert to universal
> planes!

The problem here is actually dpms. Our current dpms interface sucks
badly, since from generic code it's completely impossible to figure
out whether the pipe is still on or somehow disabled due to dpms. I'm
pondering ideas and designs right now, but my current dpms plan for
atomic includes a fix for this. So with that I'd replace this hack
with crtc->state->active check and add a WARN_ON to make sure the
drm_vblank_get doesn't fail when the pipe is supposed to be on.
-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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH] drm/plane-helper: transitional atomic plane helpers
  2014-11-02 13:19 ` [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers Daniel Vetter
  2014-11-05 16:45   ` Sean Paul
@ 2014-11-05 16:59   ` Daniel Vetter
  1 sibling, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 16:59 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

Converting a driver to the atomic interface can be a daunting
undertaking. One of the prerequisites is to have full universal planes
support.

To make that transition a bit easier this patch provides plane helpers
which use the new atomic helper callbacks just only for the plane
changes. This way the plane update functionality can be tested without
being forced to convert everything at once.

Of course a real atomic update capable driver will implement the
all plane properties through the atomic interface, so these helpers
are mostly transitional. But they can be used to enable proper
universal plane support, especially once the crtc helpers have also
been adapted.

v2: Use ->atomic_duplicate_state if available.

v3: Don't forget to call ->atomic_destroy_state if available.

v4: Fixup kerneldoc, reported by Paulo.

v5: Extract a common plane_commit helper and fix some bugs in the
plane_state setup of the plane_disable implementation.

v6: Fix issues with the cleanup of the old fb. Since transitional
helpers can be mixed we need to assume that the old fb has been set up
by a legacy path (e.g. set_config or page_flip when the primary plane
is converted to use these functions already). Hence pass an additional
old_fb parameter to plane_commit to do that cleanup work correctly.

v7:
- Fix spurious WARNING (crtc helpers really love to disable stuff
  harder) and fix array index bonghits.
- Correctly handle the lack of plane->state object, necessary for
  transitional use.
- Don't indicate failure if drm_vblank_get doesn't work - that's
  expected when the pipe is in dpms off mode.

v8: Review from Sean:
- s/fail/out/ to make the meaning of a label more clear.
- spelling fix in the commit message.

Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_plane_helper.c | 172 ++++++++++++++++++++++++++++++++++++-
 include/drm/drm_plane_helper.h     |   8 ++
 2 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 827ec1a3040b..a202b89e14eb 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -27,7 +27,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -369,3 +369,173 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
 }
 EXPORT_SYMBOL(drm_crtc_init);
+
+static int
+plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
+	     struct drm_framebuffer *old_fb)
+{
+	struct drm_plane_helper_funcs *plane_funcs;
+	struct drm_crtc *crtc[2];
+	struct drm_crtc_helper_funcs *crtc_funcs[2];
+	int i, ret = 0;
+
+	plane_funcs = plane->helper_private;
+
+	/* Since this is a transitional helper we can't assume that plane->state
+	 * is always valid. Hence we need to use plane->crtc instead of
+	 * plane->state->crtc as the old crtc. */
+	crtc[0] = plane->crtc;
+	crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
+
+	for (i = 0; i < 2; i++)
+		crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
+
+	if (plane_funcs->atomic_check) {
+		ret = plane_funcs->atomic_check(plane, plane_state);
+		if (ret)
+			goto out;
+	}
+
+	if (plane_funcs->prepare_fb && plane_state->fb) {
+		ret = plane_funcs->prepare_fb(plane, plane_state->fb);
+		if (ret)
+			goto out;
+	}
+
+	/* Point of no return, commit sw state. */
+	swap(plane->state, plane_state);
+
+	for (i = 0; i < 2; i++) {
+		if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
+			crtc_funcs[i]->atomic_begin(crtc[i]);
+	}
+
+	plane_funcs->atomic_update(plane);
+
+	for (i = 0; i < 2; i++) {
+		if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
+			crtc_funcs[i]->atomic_flush(crtc[i]);
+	}
+
+	for (i = 0; i < 2; i++) {
+		if (!crtc[i])
+			continue;
+
+		/* There's no other way to figure out whether the crtc is running. */
+		ret = drm_crtc_vblank_get(crtc[i]);
+		if (ret == 0) {
+			drm_crtc_wait_one_vblank(crtc[i]);
+			drm_crtc_vblank_put(crtc[i]);
+		}
+
+		ret = 0;
+	}
+
+	if (plane_funcs->cleanup_fb && old_fb)
+		plane_funcs->cleanup_fb(plane, old_fb);
+out:
+	if (plane_state) {
+		if (plane->funcs->atomic_destroy_state)
+			plane->funcs->atomic_destroy_state(plane, plane_state);
+		else
+			kfree(plane_state);
+	}
+
+	return ret;
+}
+
+/**
+ * drm_plane_helper_update() - Helper for primary plane update
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb,
+			    int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h)
+{
+	struct drm_plane_state *plane_state;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = crtc;
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	return plane_commit(plane, plane_state, plane->fb);
+}
+EXPORT_SYMBOL(drm_plane_helper_update);
+
+/**
+ * drm_plane_helper_disable() - Helper for primary plane disable
+ * @plane: plane to disable
+ *
+ * Provides a default plane disable handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_disable(struct drm_plane *plane)
+{
+	struct drm_plane_state *plane_state;
+
+	/* crtc helpers love to call disable functions for already disabled hw
+	 * functions. So cope with that. */
+	if (!plane->crtc)
+		return 0;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = NULL;
+	plane_state->fb = NULL;
+
+	return plane_commit(plane, plane_state, plane->fb);
+}
+EXPORT_SYMBOL(drm_plane_helper_disable);
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index 8577ec8f3e6c..92bceccaa62a 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -95,4 +95,12 @@ extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
 							 int num_formats);
 
 
+int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb,
+			    int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h);
+int drm_plane_helper_disable(struct drm_plane *plane);
+
 #endif
-- 
2.1.1

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

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

* Re: [PATCH 05/17] drm: Add atomic driver interface definitions for objects
  2014-11-05 16:26   ` Thierry Reding
@ 2014-11-05 17:04     ` Daniel Vetter
  2014-11-05 17:16       ` [Intel-gfx] " Damien Lespiau
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 17:04 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Intel Graphics Development, DRI Development

On Wed, Nov 5, 2014 at 5:26 PM, Thierry Reding <thierry.reding@gmail.com> wrote:
>> +struct drm_plane_state {
>> +     struct drm_crtc *crtc;
>> +     struct drm_framebuffer *fb;
>> +
>> +     /* Signed dest location allows it to be partially off screen */
>> +     int32_t crtc_x, crtc_y;
>> +     uint32_t crtc_w, crtc_h;
>
> Should these perhaps be unsized types? For the same reasons you argued
> the other day.
>
>> +
>> +     /* Source values are 16.16 fixed point */
>> +     uint32_t src_x, src_y;
>> +     uint32_t src_h, src_w;
>
> Do we really use the 16.16 fixed point format for these? Maybe now would
> be a good time to get rid of that if we don't need it. If they're not a
> 16.16 fixed point format they could also be unsized.

The samantics and types intentionally and precisely match what we
currently pass in through the set_plane ioctl. And yeah most drivers
can't do subpixel precise upscaling, but some hardware can do that. So
I don't see a point in changing the interface here.

I've implemented all the other stuff you've spotted.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm: Global atomic state handling
  2014-11-05 14:22         ` Daniel Vetter
@ 2014-11-05 17:06           ` Daniel Vetter
  2015-02-06  9:58             ` [Intel-gfx] " Jani Nikula
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 17:06 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Thompson, Daniel Vetter, Intel Graphics Development,
	Thierry Reding, Fengguang Wu

Some differences compared to Rob's patches again:
- Dropped the committed and checked booleans. Checking will be
  internally enforced by always calling ->atomic_check before
  ->atomic_commit. And async handling needs to be solved differently
  because the current scheme completely side-steps ww mutex deadlock
  avoidance (and so either reinvents a new deadlock avoidance wheel or
  like the current code just deadlocks).

- State for connectors needed to be added, since now they have a
  full-blown drm_connector_state (so that drivers have something to
  attach their own stuff to).

- Refcounting is gone. I plane to solve async updates differently,
  since the lock-passing scheme doesn't cut it (since it abuses ww
  mutexes). Essentially what we need for async is a simple ownership
  transfer from the caller to the driver. That doesn't need full-blown
  refcounting.

- The acquire ctx is a pointer. Real atomic callers should have that
  on their stack, legacy entry points need to put the right one
  (obtained by drm_modeset_legacy_acuire_ctx) in there.

- I've dropped all hooks except check/commit. All the begin/end
  handling is done by core functions and is the same.

- commit/check are just thin wrappers that ensure that ->check is
  always called.

- To help out with locking in the legacy implementations I've added a
  helper to just grab all locks in the backoff case.

v2: Add notices that check/commit can fail with EDEADLK.

v3:
- More consistent naming for state_alloc.
- Add state_clear which is needed for backoff and retry.

v4: Planes/connectors can switch between crtcs, and we need to be
careful that we grab the state (and locks) for both the old and new
crtc. Improve the interface functions to ensure this.

v5: Add functions to grab affected connectors for a crtc and to recompute
the crtc->enable state. This is useful for both helper and atomic ioctl
code when e.g. removing a connector.

v6: Squash in fixup from Fengguang to use ERR_CAST.

v7: Add debug output.

v8: Make checkpatch happy about kcalloc argument ordering.

v9: Improve kerneldoc in drm_crtc.h

v10:
- Fix another kcalloc argument misorder I've missed.
- More polish for kerneldoc.

v11: Clarify the ownership rules for the state object. The new rule is
that a successful drm_atomic_commit (whether synchronous or asnyc)
always inherits the state and is responsible for the clean-up. That
way async and sync ->commit functions are more similar.

v12: A few bugfixes:
- Assign state->state pointers correctly when grabbing state objects -
  we need to link them up with the global state.
- Handle a NULL crtc in set_crtc_for_plane to simplify code flow a bit
  for the callers of this function.

v13: Review from Sean:
- kerneldoc spelling fixes
- Don't overallocate states->planes.
- Handle NULL crtc in set_crtc_for_connector.

v14: Sprinkle __must_check over all functions which do wait/wound
locking to make sure callers don't forget this. Since I have ;-)

v15: Be more explicit in the kerneldoc when functions can return
-EDEADLK what to do. And that every other -errno is fatal.

v16: Indent with tabs instead of space, spotted by Ander.

v17: Review from Thierry, small kerneldoc and other naming polish.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |   4 +
 drivers/gpu/drm/Makefile       |   2 +-
 drivers/gpu/drm/drm_atomic.c   | 600 +++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h       |  65 +++++
 include/drm/drm_crtc.h         |  50 +++-
 5 files changed, 712 insertions(+), 9 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index f83d3b6ea4e5..748513b34025 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -996,6 +996,10 @@ int max_width, max_height;</synopsis>
 !Edrivers/gpu/drm/drm_modes.c
     </sect2>
     <sect2>
+      <title>Atomic Mode Setting Function Reference</title>
+!Edrivers/gpu/drm/drm_atomic.c
+    </sect2>
+    <sect2>
       <title>Frame Buffer Creation</title>
       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
 				     struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9292a761ea6d..c5e37dc459ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o
+		drm_modeset_lock.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 000000000000..ad15a88c0f74
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_plane_helper.h>
+
+static void kfree_state(struct drm_atomic_state *state)
+{
+	kfree(state->connectors);
+	kfree(state->connector_states);
+	kfree(state->crtcs);
+	kfree(state->crtc_states);
+	kfree(state->planes);
+	kfree(state->plane_states);
+	kfree(state);
+}
+
+/**
+ * drm_atomic_state_alloc - allocate atomic state
+ * @dev: DRM device
+ *
+ * This allocates an empty atomic state to track updates.
+ */
+struct drm_atomic_state *
+drm_atomic_state_alloc(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->crtcs = kcalloc(dev->mode_config.num_crtc,
+			       sizeof(*state->crtcs), GFP_KERNEL);
+	if (!state->crtcs)
+		goto fail;
+	state->crtc_states = kcalloc(dev->mode_config.num_crtc,
+				     sizeof(*state->crtc_states), GFP_KERNEL);
+	if (!state->crtc_states)
+		goto fail;
+	state->planes = kcalloc(dev->mode_config.num_total_plane,
+				sizeof(*state->planes), GFP_KERNEL);
+	if (!state->planes)
+		goto fail;
+	state->plane_states = kcalloc(dev->mode_config.num_total_plane,
+				      sizeof(*state->plane_states), GFP_KERNEL);
+	if (!state->plane_states)
+		goto fail;
+	state->connectors = kcalloc(dev->mode_config.num_connector,
+				    sizeof(*state->connectors),
+				    GFP_KERNEL);
+	if (!state->connectors)
+		goto fail;
+	state->connector_states = kcalloc(dev->mode_config.num_connector,
+					  sizeof(*state->connector_states),
+					  GFP_KERNEL);
+	if (!state->connector_states)
+		goto fail;
+
+	state->dev = dev;
+
+	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
+
+	return state;
+fail:
+	kfree_state(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_state_alloc);
+
+/**
+ * drm_atomic_state_clear - clear state object
+ * @state: atomic state
+ *
+ * When the w/w mutex algorithm detects a deadlock we need to back off and drop
+ * all locks. So someone else could sneak in and change the current modeset
+ * configuration. Which means that all the state assembled in @state is no
+ * longer an atomic update to the current state, but to some arbitrary earlier
+ * state. Which could break assumptions the driver's ->atomic_check likely
+ * relies on.
+ *
+ * Hence we must clear all cached state and completely start over, using this
+ * function.
+ */
+void drm_atomic_state_clear(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	int i;
+
+	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
+
+	for (i = 0; i < dev->mode_config.num_connector; i++) {
+		struct drm_connector *connector = state->connectors[i];
+
+		if (!connector)
+			continue;
+
+		connector->funcs->atomic_destroy_state(connector,
+						       state->connector_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc,
+						  state->crtc_states[i]);
+	}
+
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane,
+						   state->plane_states[i]);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_state_clear);
+
+/**
+ * drm_atomic_state_free - free all memory for an atomic state
+ * @state: atomic state to deallocate
+ *
+ * This frees all memory associated with an atomic state, including all the
+ * per-object state for planes, crtcs and connectors.
+ */
+void drm_atomic_state_free(struct drm_atomic_state *state)
+{
+	drm_atomic_state_clear(state);
+
+	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
+
+	kfree_state(state);
+}
+EXPORT_SYMBOL(drm_atomic_state_free);
+
+/**
+ * drm_atomic_get_crtc_state - get crtc state
+ * @state: global atomic state object
+ * @crtc: crtc to get state object for
+ *
+ * This function returns the crtc state for the given crtc, allocating it if
+ * needed. It will also grab the relevant crtc lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc)
+{
+	int ret, index;
+	struct drm_crtc_state *crtc_state;
+
+	index = drm_crtc_index(crtc);
+
+	if (state->crtc_states[index])
+		return state->crtc_states[index];
+
+	ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	if (!crtc_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
+		      crtc->base.id, crtc_state, state);
+
+	return crtc_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_crtc_state);
+
+/**
+ * drm_atomic_get_plane_state - get plane state
+ * @state: global atomic state object
+ * @plane: plane to get state object for
+ *
+ * This function returns the plane state for the given plane, allocating it if
+ * needed. It will also grab the relevant plane lock to make sure that the state
+ * is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			  struct drm_plane *plane)
+{
+	int ret, index;
+	struct drm_plane_state *plane_state;
+
+	index = drm_plane_index(plane);
+
+	if (state->plane_states[index])
+		return state->plane_states[index];
+
+	/*
+	 * TODO: We currently don't have per-plane mutexes. So instead of trying
+	 * crazy tricks with deferring plane->crtc and hoping for the best just
+	 * grab all crtc locks. Once we have per-plane locks we must update this
+	 * to only take the plane mutex.
+	 */
+	ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->plane_states[index] = plane_state;
+	state->planes[index] = plane;
+	plane_state->state = state;
+
+	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
+		      plane->base.id, plane_state, state);
+
+	if (plane_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       plane_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return plane_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_plane_state);
+
+/**
+ * drm_atomic_get_connector_state - get connector state
+ * @state: global atomic state object
+ * @connector: connector to get state object for
+ *
+ * This function returns the connector state for the given connector,
+ * allocating it if needed. It will also grab the relevant connector lock to
+ * make sure that the state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_connector_state *
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			  struct drm_connector *connector)
+{
+	int ret, index;
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_connector_state *connector_state;
+
+	index = drm_connector_index(connector);
+
+	if (state->connector_states[index])
+		return state->connector_states[index];
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	if (!connector_state)
+		return ERR_PTR(-ENOMEM);
+
+	state->connector_states[index] = connector_state;
+	state->connectors[index] = connector;
+	connector_state->state = state;
+
+	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
+		      connector->base.id, connector_state, state);
+
+	if (connector_state->crtc) {
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state,
+						       connector_state->crtc);
+		if (IS_ERR(crtc_state))
+			return ERR_CAST(crtc_state);
+	}
+
+	return connector_state;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_state);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: atomic state object for the plane
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+						       crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	plane_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
+			      plane_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state;
+
+	if (crtc) {
+		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+	}
+
+	conn_state->crtc = crtc;
+
+	if (crtc)
+		DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
+			      conn_state, crtc->base.id);
+	else
+		DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
+			      conn_state);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+/**
+ * drm_atomic_add_affected_connectors - add connectors for crtc
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function walks the current configuration and adds all connectors
+ * currently using @crtc to the atomic configuration @state. Note that this
+ * function must acquire the connection mutex. This can potentially cause
+ * unneeded seralization if the update is just for the planes on one crtc. Hence
+ * drivers and helpers should only call this when really needed (e.g. when a
+ * full modeset needs to happen due to some change).
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int ret;
+
+	ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
+		      crtc->base.id, state);
+
+	/*
+	 * Changed connectors are already in @state, so only need to look at the
+	 * current configuration.
+	 */
+	list_for_each_entry(connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
+
+/**
+ * drm_atomic_connectors_for_crtc - count number of connected outputs
+ * @state: atomic state
+ * @crtc: DRM crtc
+ *
+ * This function counts all connectors which will be connected to @crtc
+ * according to @state. Useful to recompute the enable state for @crtc.
+ */
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc)
+{
+	int nconnectors = state->dev->mode_config.num_connector;
+	int i, num_connected_connectors = 0;
+
+	for (i = 0; i < nconnectors; i++) {
+		struct drm_connector_state *conn_state;
+
+		conn_state = state->connector_states[i];
+
+		if (conn_state && conn_state->crtc == crtc)
+			num_connected_connectors++;
+	}
+
+	DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
+		      state, num_connected_connectors, crtc->base.id);
+
+	return num_connected_connectors;
+}
+EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
+
+/**
+ * drm_atomic_legacy_backoff - locking backoff for legacy ioctls
+ * @state: atomic state
+ *
+ * This function should be used by legacy entry points which don't understand
+ * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
+ *  the slowpath completed.
+ */
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
+{
+	int ret;
+
+retry:
+	drm_modeset_backoff(state->acquire_ctx);
+
+	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		goto retry;
+	ret = drm_modeset_lock_all_crtcs(state->dev,
+					 state->acquire_ctx);
+	if (ret)
+		goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_legacy_backoff);
+
+/**
+ * drm_atomic_check_only - check whether a given config would work
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_check_only(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+
+	DRM_DEBUG_KMS("checking %p\n", state);
+
+	if (config->funcs->atomic_check)
+		return config->funcs->atomic_check(state->dev, state);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_atomic_check_only);
+
+/**
+ * drm_atomic_commit - commit configuration atomically
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, false);
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_async_commit - atomic&async configuration commit
+ * @state: atomic configuration to check
+ *
+ * Note that this function can return -EDEADLK if the driver needed to acquire
+ * more locks but encountered a deadlock. The caller must then do the usual w/w
+ * backoff dance and restart. All other errors are fatal.
+ *
+ * Also note that on successful execution ownership of @state is transferred
+ * from the caller of this function to the function itself. The caller must not
+ * free or in any other way access @state. If the function fails then the caller
+ * must clean up @state itself.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+int drm_atomic_async_commit(struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &state->dev->mode_config;
+	int ret;
+
+	ret = drm_atomic_check_only(state);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
+
+	return config->funcs->atomic_commit(state->dev, state, true);
+}
+EXPORT_SYMBOL(drm_atomic_async_commit);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 000000000000..5bb15f550c42
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_H_
+#define DRM_ATOMIC_H_
+
+struct drm_atomic_state * __must_check
+drm_atomic_state_alloc(struct drm_device *dev);
+void drm_atomic_state_clear(struct drm_atomic_state *state);
+void drm_atomic_state_free(struct drm_atomic_state *state);
+
+struct drm_crtc_state * __must_check
+drm_atomic_get_crtc_state(struct drm_atomic_state *state,
+			  struct drm_crtc *crtc);
+struct drm_plane_state * __must_check
+drm_atomic_get_plane_state(struct drm_atomic_state *state,
+			   struct drm_plane *plane);
+struct drm_connector_state * __must_check
+drm_atomic_get_connector_state(struct drm_atomic_state *state,
+			       struct drm_connector *connector);
+
+int __must_check
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc);
+int __must_check
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+				  struct drm_crtc *crtc);
+int __must_check
+drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
+				   struct drm_crtc *crtc);
+int
+drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
+			       struct drm_crtc *crtc);
+
+void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+
+int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
+int __must_check drm_atomic_commit(struct drm_atomic_state *state);
+int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
+
+#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3554868dbf09..c7a3400173a8 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -227,7 +227,7 @@ struct drm_bridge;
 struct drm_atomic_state;
 
 /**
- * struct drm_crtc_state - mutable crtc state
+ * struct drm_crtc_state - mutable CRTC state
  * @enable: whether the CRTC should be enabled, gates all other state
  * @mode: current mode timings
  * @event: optional pointer to a DRM event to signal upon completion of the
@@ -235,7 +235,7 @@ struct drm_atomic_state;
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_crtc_state {
-	bool enable        : 1;
+	bool enable;
 
 	struct drm_display_mode mode;
 
@@ -314,7 +314,7 @@ struct drm_crtc_funcs {
 	/* atomic update handling */
 	struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
 	void (*atomic_destroy_state)(struct drm_crtc *crtc,
-				     struct drm_crtc_state *cstate);
+				     struct drm_crtc_state *state);
 	int (*atomic_set_property)(struct drm_crtc *crtc,
 				   struct drm_crtc_state *state,
 				   struct drm_property *property,
@@ -417,7 +417,7 @@ struct drm_crtc {
 
 /**
  * struct drm_connector_state - mutable connector state
- * @crtc: crtc to connect connector to, NULL if disabled
+ * @crtc: CRTC to connect connector to, NULL if disabled
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_connector_state {
@@ -441,7 +441,6 @@ struct drm_connector_state {
  * @atomic_destroy_state: destroy an atomic state for this connector
  * @atomic_set_property: set a property on an atomic state for this connector
  *
- *
  * Each CRTC may have one or more connectors attached to it.  The functions
  * below allow the core DRM code to control connectors, enumerate available modes,
  * etc.
@@ -469,7 +468,7 @@ struct drm_connector_funcs {
 	/* atomic update handling */
 	struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
 	void (*atomic_destroy_state)(struct drm_connector *connector,
-				     struct drm_connector_state *cstate);
+				     struct drm_connector_state *state);
 	int (*atomic_set_property)(struct drm_connector *connector,
 				   struct drm_connector_state *state,
 				   struct drm_property *property,
@@ -640,7 +639,7 @@ struct drm_connector {
 /**
  * struct drm_plane_state - mutable plane state
  * @crtc: currently bound CRTC, NULL if disabled
- * @fb: currently bound fb
+ * @fb: currently bound framebuffer
  * @crtc_x: left position of visible portion of plane on crtc
  * @crtc_y: upper position of visible portion of plane on crtc
  * @crtc_w: width of visible portion of plane on crtc
@@ -697,7 +696,7 @@ struct drm_plane_funcs {
 	/* atomic update handling */
 	struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
 	void (*atomic_destroy_state)(struct drm_plane *plane,
-				     struct drm_plane_state *cstate);
+				     struct drm_plane_state *state);
 	int (*atomic_set_property)(struct drm_plane *plane,
 				   struct drm_plane_state *state,
 				   struct drm_property *property,
@@ -794,6 +793,32 @@ struct drm_bridge {
 };
 
 /**
+ * struct struct drm_atomic_state - the global state object for atomic updates
+ * @dev: parent DRM device
+ * @flags: state flags like async update
+ * @planes: pointer to array of plane pointers
+ * @plane_states: pointer to array of plane states pointers
+ * @crtcs: pointer to array of CRTC pointers
+ * @crtc_states: pointer to array of CRTC states pointers
+ * @connectors: pointer to array of connector pointers
+ * @connector_states: pointer to array of connector states pointers
+ * @acquire_ctx: acquire context for this atomic modeset state update
+ */
+struct drm_atomic_state {
+	struct drm_device *dev;
+	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **plane_states;
+	struct drm_crtc **crtcs;
+	struct drm_crtc_state **crtc_states;
+	struct drm_connector **connectors;
+	struct drm_connector_state **connector_states;
+
+	struct drm_modeset_acquire_ctx *acquire_ctx;
+};
+
+
+/**
  * struct drm_mode_set - new values for a CRTC config change
  * @fb: framebuffer to use for new config
  * @crtc: CRTC whose configuration we're about to change
@@ -824,6 +849,9 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
+ * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_commit: commit an atomic state update previously verified with
+ * 	atomic_check()
  *
  * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
  * involve drivers.
@@ -833,6 +861,12 @@ struct drm_mode_config_funcs {
 					     struct drm_file *file_priv,
 					     struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
+
+	int (*atomic_check)(struct drm_device *dev,
+			    struct drm_atomic_state *a);
+	int (*atomic_commit)(struct drm_device *dev,
+			     struct drm_atomic_state *a,
+			     bool async);
 };
 
 /**
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [Intel-gfx] [PATCH 05/17] drm: Add atomic driver interface definitions for objects
  2014-11-05 17:04     ` Daniel Vetter
@ 2014-11-05 17:16       ` Damien Lespiau
  0 siblings, 0 replies; 77+ messages in thread
From: Damien Lespiau @ 2014-11-05 17:16 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Wed, Nov 05, 2014 at 06:04:59PM +0100, Daniel Vetter wrote:
> On Wed, Nov 5, 2014 at 5:26 PM, Thierry Reding <thierry.reding@gmail.com> wrote:
> >> +struct drm_plane_state {
> >> +     struct drm_crtc *crtc;
> >> +     struct drm_framebuffer *fb;
> >> +
> >> +     /* Signed dest location allows it to be partially off screen */
> >> +     int32_t crtc_x, crtc_y;
> >> +     uint32_t crtc_w, crtc_h;
> >
> > Should these perhaps be unsized types? For the same reasons you argued
> > the other day.
> >
> >> +
> >> +     /* Source values are 16.16 fixed point */
> >> +     uint32_t src_x, src_y;
> >> +     uint32_t src_h, src_w;
> >
> > Do we really use the 16.16 fixed point format for these? Maybe now would
> > be a good time to get rid of that if we don't need it. If they're not a
> > 16.16 fixed point format they could also be unsized.
> 
> The samantics and types intentionally and precisely match what we
> currently pass in through the set_plane ioctl. And yeah most drivers
> can't do subpixel precise upscaling, but some hardware can do that. So
> I don't see a point in changing the interface here.
> 
> I've implemented all the other stuff you've spotted.

Just a pass by comment, it'd be awesome to have a fixed point 16.16 type
at some point so we don't have to always specify that an uint32_t
variable happens to be 16.16.

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

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

* Re: [PATCH 09/17] drm/crtc-helper: Transitional functions using atomic plane helpers
  2014-11-02 13:19 ` [PATCH 09/17] drm/crtc-helper: Transitional functions using " Daniel Vetter
@ 2014-11-05 17:42   ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-05 17:42 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:22PM +0100, Daniel Vetter wrote:
> These two functions allow drivers to reuse their atomic plane helpers
> functions for the primary plane to implement the interfaces required
> by the crtc helpers for the legacy ->set_config callback.
>
> This is purely transitional and won't be used once the driver is fully
> converted. But it allows partial conversions to the atomic plane
> helpers which are functional.
>
> v2:
> - Use ->atomic_duplicate_state if available.
> - Don't forget to run crtc_funcs->atomic_check.
>
> v3: Shift source coordinates correctly for 16.16 fixed point.
>
> v4: Don't forget to call ->atomic_destroy_state if available.
>
> v5: Fixup kerneldoc.
>
> v6: Reuse the plane_commit function from the transitional plane
> helpers to avoid too much duplication.
>
> v7:
> - Remove some stale comment.
> - Correctly handle the lack of plane->state object, necessary for
>   transitional use.
>
> v8: Fixup an embarrassing h/vdisplay mixup.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_crtc_helper.c  | 110 +++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_plane_helper.c |  10 ++--
>  include/drm/drm_crtc.h             |   4 ++
>  include/drm/drm_crtc_helper.h      |   7 +++
>  include/drm/drm_plane_helper.h     |   4 ++
>  5 files changed, 130 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 6c65a0a28fbd..95ecbb131053 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -38,6 +38,7 @@
>  #include <drm/drm_fourcc.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_helper.h>
> +#include <drm/drm_plane_helper.h>
>  #include <drm/drm_edid.h>
>
>  MODULE_AUTHOR("David Airlie, Jesse Barnes");
> @@ -888,3 +889,112 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
>   drm_modeset_unlock_all(dev);
>  }
>  EXPORT_SYMBOL(drm_helper_resume_force_mode);
> +
> +/**
> + * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
> + * @crtc: DRM CRTC
> + * @mode: DRM display mode which userspace requested
> + * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
> + * @x: x offset of the CRTC scanout area on the underlying framebuffer
> + * @y: y offset of the CRTC scanout area on the underlying framebuffer
> + * @old_fb: previous framebuffer
> + *
> + * This function implements a callback useable as the ->mode_set callback
> + * required by the crtc helpers. Besides the atomic plane helper functions for
> + * the primary plane the driver must also provide the ->mode_set_nofb callback
> + * to set up the crtc.
> + *
> + * This is a transitional helper useful for converting drivers to the atomic
> + * interfaces.
> + */
> +int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
> +     struct drm_display_mode *adjusted_mode, int x, int y,
> +     struct drm_framebuffer *old_fb)
> +{
> + struct drm_crtc_state *crtc_state;
> + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
> + int ret;
> +
> + if (crtc->funcs->atomic_duplicate_state)
> + crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
> + else if (crtc->state)
> + crtc_state = kmemdup(crtc->state, sizeof(*crtc_state),
> +     GFP_KERNEL);
> + else
> + crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
> + if (!crtc_state)
> + return -ENOMEM;
> +
> + crtc_state->enable = true;
> + crtc_state->planes_changed = true;
> + drm_mode_copy(&crtc_state->mode, mode);
> + drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
> +
> + if (crtc_funcs->atomic_check) {
> + ret = crtc_funcs->atomic_check(crtc, crtc_state);
> + if (ret) {
> + kfree(crtc_state);
> +
> + return ret;
> + }
> + }
> +
> + swap(crtc->state, crtc_state);
> +
> + crtc_funcs->mode_set_nofb(crtc);
> +
> + if (crtc_state) {
> + if (crtc->funcs->atomic_destroy_state)
> + crtc->funcs->atomic_destroy_state(crtc, crtc_state);
> + else
> + kfree(crtc_state);
> + }
> +
> + return drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
> +}
> +EXPORT_SYMBOL(drm_helper_crtc_mode_set);
> +
> +/**
> + * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
> + * @crtc: DRM CRTC
> + * @x: x offset of the CRTC scanout area on the underlying framebuffer
> + * @y: y offset of the CRTC scanout area on the underlying framebuffer
> + * @old_fb: previous framebuffer
> + *
> + * This function implements a callback useable as the ->mode_set_base used
> + * required by the crtc helpers. The driver must provide the atomic plane helper
> + * functions for the primary plane.
> + *
> + * This is a transitional helper useful for converting drivers to the atomic
> + * interfaces.
> + */
> +int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> +  struct drm_framebuffer *old_fb)
> +{
> + struct drm_plane_state *plane_state;
> + struct drm_plane *plane = crtc->primary;
> +
> + if (plane->funcs->atomic_duplicate_state)
> + plane_state = plane->funcs->atomic_duplicate_state(plane);
> + else if (plane->state)
> + plane_state = kmemdup(plane->state, sizeof(*plane_state),
> +      GFP_KERNEL);
> + else
> + plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
> + if (!plane_state)
> + return -ENOMEM;
> +
> + plane_state->crtc = crtc;
> + plane_state->fb = crtc->primary->fb;
> + plane_state->crtc_x = 0;
> + plane_state->crtc_y = 0;
> + plane_state->crtc_h = crtc->mode.vdisplay;
> + plane_state->crtc_w = crtc->mode.hdisplay;
> + plane_state->src_x = x << 16;
> + plane_state->src_y = y << 16;
> + plane_state->src_h = crtc->mode.vdisplay << 16;
> + plane_state->src_w = crtc->mode.hdisplay << 16;
> +
> + return drm_plane_helper_commit(plane, plane_state, old_fb);
> +}
> +EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> index 45aa8c98e3fb..40ecb2c6e858 100644
> --- a/drivers/gpu/drm/drm_plane_helper.c
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -370,9 +370,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>  }
>  EXPORT_SYMBOL(drm_crtc_init);
>
> -static int
> -plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
> -     struct drm_framebuffer *old_fb)
> +int drm_plane_helper_commit(struct drm_plane *plane,
> +    struct drm_plane_state *plane_state,
> +    struct drm_framebuffer *old_fb)
>  {
>   struct drm_plane_helper_funcs *plane_funcs;
>   struct drm_crtc *crtc[2];
> @@ -497,7 +497,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
>   plane_state->src_h = src_h;
>   plane_state->src_w = src_w;
>
> - return plane_commit(plane, plane_state, plane->fb);
> + return drm_plane_helper_commit(plane, plane_state, plane->fb);
>  }
>  EXPORT_SYMBOL(drm_plane_helper_update);
>
> @@ -536,6 +536,6 @@ int drm_plane_helper_disable(struct drm_plane *plane)
>   plane_state->crtc = NULL;
>   plane_state->fb = NULL;
>
> - return plane_commit(plane, plane_state, plane->fb);
> + return drm_plane_helper_commit(plane, plane_state, plane->fb);
>  }
>  EXPORT_SYMBOL(drm_plane_helper_disable);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index d0068b7af678..77ff8992a3b7 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -230,6 +230,7 @@ struct drm_atomic_state;
>   * struct drm_crtc_state - mutable crtc state
>   * @enable: whether the CRTC should be enabled, gates all other state
>   * @planes_changed: for use by helpers and drivers when computing state updates
> + * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
>   * @mode: current mode timings
>   * @event: optional pointer to a DRM event to signal upon completion of the
>   * state update
> @@ -241,6 +242,9 @@ struct drm_crtc_state {
>   /* computed state bits used by helpers and drivers */
>   bool planes_changed : 1;
>
> + /* adjusted_mode: for use by helpers and drivers */
> + struct drm_display_mode adjusted_mode;
> +
>   struct drm_display_mode mode;
>
>   struct drm_pending_vblank_event *event;
> diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
> index adec48b27aa5..7adbb65ea8ae 100644
> --- a/include/drm/drm_crtc_helper.h
> +++ b/include/drm/drm_crtc_helper.h
> @@ -68,6 +68,7 @@ struct drm_crtc_helper_funcs {
>   int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
>   struct drm_display_mode *adjusted_mode, int x, int y,
>   struct drm_framebuffer *old_fb);
> + void (*mode_set_nofb)(struct drm_crtc *crtc);
>
>   /* Move the crtc on the current fb to the given position *optional* */
>   int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
> @@ -167,6 +168,12 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
>
>  extern void drm_helper_resume_force_mode(struct drm_device *dev);
>
> +int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
> +     struct drm_display_mode *adjusted_mode, int x, int y,
> +     struct drm_framebuffer *old_fb);
> +int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> +  struct drm_framebuffer *old_fb);
> +
>  /* drm_probe_helper.c */
>  extern int drm_helper_probe_single_connector_modes(struct drm_connector
>     *connector, uint32_t maxX,
> diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
> index 8a0709704af0..62acb3c940b4 100644
> --- a/include/drm/drm_plane_helper.h
> +++ b/include/drm/drm_plane_helper.h
> @@ -102,4 +102,8 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
>      uint32_t src_w, uint32_t src_h);
>  int drm_plane_helper_disable(struct drm_plane *plane);
>
> +/* For use by drm_crtc_helper.c */
> +int drm_plane_helper_commit(struct drm_plane *plane,
> +    struct drm_plane_state *plane_state,
> +    struct drm_framebuffer *old_fb);
>  #endif
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces
  2014-11-02 13:19 ` [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces Daniel Vetter
@ 2014-11-05 18:53   ` Sean Paul
  2014-11-05 21:44     ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-05 18:53 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:23PM +0100, Daniel Vetter wrote:
> So this is finally the integration of the crtc and plane helper
> interfaces into the atomic helper functions.
>
> In the check function we now have a few steps:
>
> - First we update the output routing and figure out which crtcs need a
>   full mode set. Suitable encoders are selected using ->best_encoder,
>   with the same semantics as the crtc helpers of implicitly disabling
>   all connectors currently using the encoder.
>
> - Then we pull all other connectors into the state update which feed
>   from a crtc which changes. This must be done do catch mode changes
>   and similar updates - atomic updates are differences on top of the
>   current state.
>
> - Then we call all the various ->mode_fixup to compute the adjusted
>   mode. Note that here we have a slight semantic difference compared
>   to the crtc helpers: We have not yet updated the encoder->crtc link
>   when calling the encoder's ->mode_fixup function. But that's a
>   requirement when converting to atomic since we want to prepare the
>   entire state completely contained with the over drm_atomic_state
>   structure. So this must be carefully checked when converting drivers
>   over to atomic helpers.
>
> - Finally we do call the atomic_check functions on planes and crtcs.
>
> The commit function is also quite a beast:
>
> - The only step that can fail is done first, namely pinning the
>   framebuffers. After that we cross the point of no return, an async
>   commit would push all that into the worker thread.
>
> - The disabling of encoders and connectors is a bit tricky, since
>   depending upon the final state we need to select different crtc
>   helper functions.
>
> - Software tracking is a bit clarified compared to the crtc helpers:
>   We commit the software state before starting to touch the hardware,
>   like crtc helpers. But since we just swap them we still have the old
>   state (i.e. the current hw state) around, which is really handy to
>   write simple disable functions. So no more
>   drm_crtc_helper_disable_all_unused_functions kind of fun because
>   we're leaving unused crtcs/encoders behind. Everything gets shut
>   down in-order now, which is one of the key differences of the i915
>   helpers compared to crtc helpers and a really nice additional
>   guarantee.
>
> - Like with the plane helpers the atomic commit function waits for one
>   vblank to pass before calling the framebuffer cleanup function.
>
> Compared to Rob's helper approach there's a bunch of upsides:
>
> - All the interfaces which can fail are called in the ->check hook
>   (i.e. ->best_match and the various ->mode_fixup hooks). This means
>   that drivers can just reuse those functions and don't need to move
>   everything into ->atomic_check callbacks. If drivers have no need
>   for additional constraint checking beyong their existing crtc

s/beyong/beyond/

>   helper callbacks they don't need to do anything.
>
> - The actual commit operation is properly stage: First we prepare
>   framebuffers, which can potentially still fail (due to memory
>   exhausting). This is important for the async case, where this must
>   be done synchronously to correctly return errors.
>
> - The output configuration changes (done with crtc helper functions)
>   and the plane update (using atomic plane helpers) are correctly
>   interleaved: First we shut down any crtcs that need changing, then
>   we update planes and finally we enable everything again. Hardware
>   without GO bits must be more careful with ordering, which this
>   sequence enables.
>
> - Also for hardware with shared output resources (like display PLLs)
>   we first must shut down the old configuration before we can enable
>   the new one. Otherwise we can hit an impossible intermediate state
>   where there's not enough PLLs (which is the point behind atomic
>   updates).
>
> v2:
> - Ensure that users of ->check update crtc_state->enable correctly.
> - Update the legacy state in crtc/plane structures. Eventually we want
>   to remove that, but for now the drm core still expects this (especially
>   the plane->fb pointer).
>
> v3: A few changes for better async handling:
>
> - Reorder the software side state commit so that it happens all before
>   we touch the hardware. This way async support becomes very easy
>   since we can punt all the actual hw touching to a worker thread. And
>   as long as we synchronize with that thread (flushing or cancelling,
>   depending upon what the driver can handle) before we commit the next
>   software state there's no need for any locking in the worker thread
>   at all. Which greatly simplifies things.
>
>   And as long as we synchronize with all relevant threads we can have
>   a lot of them (e.g. per-crtc for per-crtc updates) running in
>   parallel.
>
> - Expose pre/post plane commit steps separately. We need to expose the
>   actual hw commit step anyway for drivers to be able to implement
>   asynchronous commit workers. But if we expose pre/post and plane
>   commit steps individually we allow drivers to selectively use atomic
>   helpers.
>
> - I've forgotten to call encoder/bridge ->mode_set functions, fix
>   this.
>
> v4: Add debug output and fix a mixup between current and new state
> that resulted in crtcs not getting updated correctly. And in an
> Oops ...
>
> v5:
> - Be kind to driver writers in the vblank wait functions.. if thing
>   aren't working yet, and vblank irq will never come, then let's not
>   block forever.. especially under console-lock.
> - Correctly clear connector_state->best_encoder when disabling.
>   Spotted while trying to understand a report from Rob Clark.
> - Only steal encoder if it actually changed, otherwise hilarity ensues
>   if we steal from the current connector and so set the ->crtc pointer
>   unexpectedly to NULL. Reported by Rob Clark.
> - Bail out in disable_outputs if an output currently doesn't have a
>   best_encoder - this means it's already disabled.
>
> v6: Fixupe kerneldoc as reported by Paulo. And also fix up kerneldoc

s/Fixupe/Fixup/

> in drm_crtc.h.
>
> v7: Take ownership of the atomic state and clean it up with
> drm_atomic_state_free().
>
> v8 Various improvements all over:
> - Polish code comments and kerneldoc.
> - Improve debug output to make sure all failure cases are logged.
> - Treat enabled crtc with no connectors as invalid input from userspace.
> - Don't ignore the return value from mode_fixup().
>
> v9:
> - Improve debug output for crtc_state->mode_changed.
>
> v10:
> - Fixup the vblank waiting code to properly balance the vblank_get/put
>   calls.
> - Better comments when checking/computing crtc->mode_changed
>
> v11: Fixup the encoder stealing logic: We can't look at encoder->crtc
> since that's not in the atomic state structures and might be updated
> asynchronously in and async commit. Instead we need to inspect all the
> connector states and check whether the encoder is currently in used
> and if so, on which crtc.
>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Cc: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---

Overall, this looks really good. I just have a couple minor comments.

Also, it seems like my mutt->gmail workflow is mangling the patch's
indentation, sorry 'bout that.



>  drivers/gpu/drm/drm_atomic_helper.c | 692 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_helper.c   |   1 +
>  include/drm/drm_atomic_helper.h     |   8 +
>  include/drm/drm_crtc.h              |  10 +
>  4 files changed, 711 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 55a8eb2678b0..887e1971c915 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -29,6 +29,7 @@
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
>
>  static void
>  drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
> @@ -57,6 +58,327 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
>   }
>  }
>
> +static struct drm_crtc *
> +get_current_crtc_for_encoder(struct drm_device *dev,
> +     struct drm_encoder *encoder)
> +{
> + struct drm_mode_config *config = &dev->mode_config;
> + struct drm_connector *connector;
> +
> + WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
> +
> + list_for_each_entry(connector, &config->connector_list, head) {
> + if (connector->state->best_encoder != encoder)
> + continue;
> +
> + return connector->state->crtc;
> + }
> +
> + return NULL;
> +}
> +
> +static int
> +steal_encoder(struct drm_atomic_state *state,
> +      struct drm_encoder *encoder,
> +      struct drm_crtc *encoder_crtc)
> +{
> + struct drm_mode_config *config = &state->dev->mode_config;
> + struct drm_crtc_state *crtc_state;
> + struct drm_connector *connector;
> + struct drm_connector_state *connector_state;
> +
> + /*
> + * We can only steal an encoder coming from a connector, which means we
> + * must already hold the connection_mutex.
> + */
> + WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
> +
> + DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n",
> +      encoder->base.id, encoder->name,
> +      encoder_crtc->base.id);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc);
> + if (IS_ERR(crtc_state))
> + return PTR_ERR(crtc_state);
> +
> + crtc_state->mode_changed = true;
> +
> + list_for_each_entry(connector, &config->connector_list, head) {
> + if (connector->state->best_encoder != encoder)
> + continue;
> +
> + DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n",
> +      connector->base.id,
> +      connector->name);
> +
> + connector_state = drm_atomic_get_connector_state(state,
> + connector);
> + if (IS_ERR(connector_state))
> + return PTR_ERR(connector_state);
> +
> + connector_state->crtc = NULL;
> + connector_state->best_encoder = NULL;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +update_connector_routing(struct drm_atomic_state *state, int conn_idx)
> +{
> + struct drm_connector_helper_funcs *funcs;
> + struct drm_encoder *new_encoder;
> + struct drm_connector *connector;
> + struct drm_connector_state *connector_state;
> + struct drm_crtc_state *crtc_state;
> + int idx, ret;
> +
> + connector = state->connectors[conn_idx];
> + connector_state = state->connector_states[conn_idx];
> +
> + if (!connector)
> + return 0;
> +
> + DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n",
> + connector->base.id,
> + connector->name);
> +
> + if (connector->state->crtc != connector_state->crtc) {
> + if (connector->state->crtc) {
> + idx = drm_crtc_index(connector->state->crtc);
> +
> + crtc_state = state->crtc_states[idx];
> + crtc_state->mode_changed = true;
> + }
> +
> + if (connector_state->crtc) {
> + idx = drm_crtc_index(connector_state->crtc);
> +
> + crtc_state = state->crtc_states[idx];
> + crtc_state->mode_changed = true;
> + }
> + }
> +
> + if (!connector_state->crtc) {
> + DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n",
> + connector->base.id,
> + connector->name);
> +
> + connector_state->best_encoder = NULL;
> +
> + return 0;
> + }
> +
> + funcs = connector->helper_private;
> + new_encoder = funcs->best_encoder(connector);
> +
> + if (!new_encoder) {
> + DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n",
> +      connector->base.id,
> +      connector->name);
> + return -EINVAL;
> + }
> +
> + if (new_encoder != connector_state->best_encoder) {

nit: If you just returned early when the encoder doesn't change, you can save
indentation and line breaks.

> + struct drm_crtc *encoder_crtc;
> +
> + encoder_crtc = get_current_crtc_for_encoder(state->dev,
> +    new_encoder);
> +
> + if (encoder_crtc) {
> + ret = steal_encoder(state, new_encoder, encoder_crtc);
> + if (ret) {
> + DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n",
> +      connector->base.id,
> +      connector->name);
> + return ret;
> + }
> + }
> +
> + connector_state->best_encoder = new_encoder;
> + idx = drm_crtc_index(connector_state->crtc);
> +
> + crtc_state = state->crtc_states[idx];
> + crtc_state->mode_changed = true;
> + }
> +
> + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
> +      connector->base.id,
> +      connector->name,
> +      new_encoder->base.id,
> +      new_encoder->name,
> +      connector_state->crtc->base.id);
> +
> + return 0;
> +}
> +
> +static int
> +mode_fixup(struct drm_atomic_state *state)
> +{
> + int ncrtcs = state->dev->mode_config.num_crtc;
> + int nconnectors = state->dev->mode_config.num_connector;
> + struct drm_crtc_state *crtc_state;
> + struct drm_connector_state *conn_state;
> + int i;
> + bool ret;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + crtc_state = state->crtc_states[i];
> +
> + if (!crtc_state || !crtc_state->mode_changed)
> + continue;
> +
> + drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode);
> + }
> +
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_encoder_helper_funcs *funcs;
> + struct drm_encoder *encoder;
> +
> + conn_state = state->connector_states[i];
> +
> + if (!conn_state)
> + continue;
> +
> + WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc);
> +
> + if (!conn_state->crtc || !conn_state->best_encoder)
> + continue;
> +
> + crtc_state =
> + state->crtc_states[drm_crtc_index(conn_state->crtc)];
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call ->mode_fixup twice.
> + */
> + encoder = conn_state->best_encoder;
> + funcs = encoder->helper_private;
> +
> + if (encoder->bridge && encoder->bridge->funcs->mode_fixup) {
> + ret = encoder->bridge->funcs->mode_fixup(
> + encoder->bridge, &crtc_state->mode,
> + &crtc_state->adjusted_mode);
> + if (!ret) {
> + DRM_DEBUG_KMS("Bridge fixup failed\n");
> + return -EINVAL;
> + }
> + }
> +
> +
> + ret = funcs->mode_fixup(encoder, &crtc_state->mode,
> + &crtc_state->adjusted_mode);
> + if (!ret) {
> + DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
> +      encoder->base.id, encoder->name);
> + return -EINVAL;
> + }
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc;
> +
> + crtc_state = state->crtc_states[i];
> + crtc = state->crtcs[i];
> +
> + if (!crtc_state || !crtc_state->mode_changed)
> + continue;
> +
> + funcs = crtc->helper_private;
> + ret = funcs->mode_fixup(crtc, &crtc_state->mode,
> + &crtc_state->adjusted_mode);
> + if (!ret) {
> + DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n",
> +      crtc->base.id);
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +drm_atomic_helper_check_prepare(struct drm_device *dev,
> + struct drm_atomic_state *state)
> +{
> + int ncrtcs = dev->mode_config.num_crtc;
> + int nconnectors = dev->mode_config.num_connector;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + int i, ret;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + crtc = state->crtcs[i];
> + crtc_state = state->crtc_states[i];
> +
> + if (!crtc)
> + continue;
> +
> + if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) {
> + DRM_DEBUG_KMS("[CRTC:%d] mode changed\n",
> +      crtc->base.id);
> + crtc_state->mode_changed = true;
> + }
> +
> + if (crtc->state->enable != crtc_state->enable) {
> + DRM_DEBUG_KMS("[CRTC:%d] state changed\n",

nit: s/state/enable/

> +      crtc->base.id);
> + crtc_state->mode_changed = true;
> + }
> + }
> +
> + for (i = 0; i < nconnectors; i++) {
> + /*
> + * This only sets crtc->mode_changed for routing changes,
> + * drivers must set crtc->mode_changed themselves when connector
> + * properties need to be updated.
> + */
> + ret = update_connector_routing(state, i);
> + if (ret)
> + return ret;
> + }
> +
> + /*
> + * After all the routing has been prepared we need to add in any
> + * connector which is itself unchanged, but who's crtc changes it's
> + * configuration. This must be done before calling mode_fixup in case a
> + * crtc only changed its mode but has the same set of connectors.
> + */
> + for (i = 0; i < ncrtcs; i++) {
> +
> + crtc = state->crtcs[i];
> + crtc_state = state->crtc_states[i];
> +
> + if (!crtc)
> + continue;
> +
> + if (crtc_state->mode_changed) {

nit: Flipping this check and moving it up into the !crtc if above saves a bit of
indentation

> + bool has_connectors;
> +
> + DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
> +      crtc->base.id,
> +      crtc_state->enable ? 'y' : 'n');
> +
> + ret = drm_atomic_add_affected_connectors(state, crtc);
> + if (ret < 0)

I think if (ret != 0) is more appropriate here

> + return ret;
> +
> + has_connectors = drm_atomic_connectors_for_crtc(state,
> + crtc);
> +
> + if (crtc_state->enable != has_connectors) {

This makes me a little nervous. Even though has_connectors is a bool,
drm_atomic_connectors_for_crtc returns an int, and this seems like something
that someone might "fix" in the future.

[PATCH] drm/atomic: Use proper type for drm_atomic_connectors_for_crtc


> + DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n",
> +      crtc->base.id);
> +
> + return -EINVAL;
> + }
> + }
> + }
> +
> + return mode_fixup(state);
> +}
> +
>  /**
>   * drm_atomic_helper_check - validate state object
>   * @dev: DRM device
> @@ -78,6 +400,10 @@ int drm_atomic_helper_check(struct drm_device *dev,
>   int ncrtcs = dev->mode_config.num_crtc;
>   int i, ret = 0;
>
> + ret = drm_atomic_helper_check_prepare(dev, state);
> + if (ret)
> + return ret;
> +
>   for (i = 0; i < nplanes; i++) {
>   struct drm_plane_helper_funcs *funcs;
>   struct drm_plane *plane = state->planes[i];
> @@ -125,6 +451,372 @@ int drm_atomic_helper_check(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_check);
>
> +static void
> +disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + int ncrtcs = old_state->dev->mode_config.num_crtc;
> + int nconnectors = old_state->dev->mode_config.num_connector;
> + int i;
> +
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector_state *old_conn_state;
> + struct drm_connector *connector;
> + struct drm_encoder_helper_funcs *funcs;
> + struct drm_encoder *encoder;
> +
> + old_conn_state = old_state->connector_states[i];
> + connector = old_state->connectors[i];
> +
> + /* Shut down everything that's in the changeset and currently
> + * still on. So need to check the old, saved state. */
> + if (!old_conn_state || !old_conn_state->crtc)
> + continue;
> +
> + encoder = connector->state->best_encoder;
> +
> + if (!encoder)
> + continue;
> +
> + funcs = encoder->helper_private;
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call call disable hooks twice.
> + */
> + if (encoder->bridge)
> + encoder->bridge->funcs->disable(encoder->bridge);
> +
> + /* Right function depends upon target state. */
> + if (connector->state->crtc)
> + funcs->prepare(encoder);
> + else if (funcs->disable)
> + funcs->disable(encoder);
> + else
> + funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
> +
> + if (encoder->bridge)
> + encoder->bridge->funcs->post_disable(encoder->bridge);
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc;
> +
> + crtc = old_state->crtcs[i];
> +
> + /* Shut down everything that needs a full modeset. */
> + if (!crtc || !crtc->state->mode_changed)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + /* Right function depends upon target state. */
> + if (crtc->state->enable)
> + funcs->prepare(crtc);
> + else if (funcs->disable)
> + funcs->disable(crtc);
> + else
> + funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
> + }
> +}
> +
> +static void
> +set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + int nconnectors = dev->mode_config.num_connector;
> + int ncrtcs = old_state->dev->mode_config.num_crtc;
> + int i;
> +
> + /* clear out existing links */
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector *connector;
> +
> + connector = old_state->connectors[i];
> +
> + if (!connector || !connector->encoder)
> + continue;
> +
> + WARN_ON(!connector->encoder->crtc);
> +
> + connector->encoder->crtc = NULL;
> + connector->encoder = NULL;
> + }
> +
> + /* set new links */
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector *connector;
> +
> + connector = old_state->connectors[i];
> +
> + if (!connector || !connector->state->crtc)
> + continue;
> +
> + if (WARN_ON(!connector->state->best_encoder))
> + continue;
> +
> + connector->encoder = connector->state->best_encoder;
> + connector->encoder->crtc = connector->state->crtc;
> + }
> +
> + /* set legacy state in the crtc structure */
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc *crtc;
> +
> + crtc = old_state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + crtc->mode = crtc->state->mode;
> + crtc->enabled = crtc->state->enable;
> + crtc->x = crtc->primary->state->src_x >> 16;
> + crtc->y = crtc->primary->state->src_y >> 16;
> + }
> +}
> +
> +static void
> +crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + int ncrtcs = old_state->dev->mode_config.num_crtc;
> + int nconnectors = old_state->dev->mode_config.num_connector;
> + int i;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc;
> +
> + crtc = old_state->crtcs[i];
> +
> + if (!crtc || !crtc->state->mode_changed)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + if (crtc->state->enable)
> + funcs->mode_set_nofb(crtc);
> + }
> +
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector *connector;
> + struct drm_crtc_state *new_crtc_state;
> + struct drm_encoder_helper_funcs *funcs;
> + struct drm_encoder *encoder;
> + struct drm_display_mode *mode, *adjusted_mode;
> +
> + connector = old_state->connectors[i];
> +
> + if (!connector || !connector->state->best_encoder)
> + continue;
> +
> + encoder = connector->state->best_encoder;
> + funcs = encoder->helper_private;
> + new_crtc_state = connector->state->crtc->state;
> + mode = &new_crtc_state->mode;
> + adjusted_mode = &new_crtc_state->adjusted_mode;
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call call mode_set hooks twice.
> + */
> + funcs->mode_set(encoder, mode, adjusted_mode);
> +
> + if (encoder->bridge && encoder->bridge->funcs->mode_set)
> + encoder->bridge->funcs->mode_set(encoder->bridge,
> + mode, adjusted_mode);
> + }
> +}
> +
> +/**
> + * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates
> + * @dev: DRM device
> + * @state: atomic state
> + *
> + * This function commits the modeset changes that need to be committed before
> + * updating planes. It shuts down all the outputs that need to be shut down and
> + * prepares them (if requried) with the new mode.

s/requried/required/

> + */
> +void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
> + struct drm_atomic_state *state)
> +{
> + disable_outputs(dev, state);
> + set_routing_links(dev, state);
> + crtc_set_mode(dev, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes);
> +
> +/**
> + * drm_atomic_helper_commit_post_planes - modeset commit after plane updates
> + * @dev: DRM device
> + * @old_state: atomic state object with old state structures
> + *
> + * This function commits the modeset changes that need to be committed after
> + * updating planes: It enables all the outputs with the new configuration which
> + * had to be turned off for the update.
> + */
> +void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
> +  struct drm_atomic_state *old_state)
> +{
> + int ncrtcs = old_state->dev->mode_config.num_crtc;
> + int nconnectors = old_state->dev->mode_config.num_connector;
> + int i;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc_helper_funcs *funcs;
> + struct drm_crtc *crtc;
> +
> + crtc = old_state->crtcs[i];
> +
> + /* Need to filter out CRTCs where only planes change. */
> + if (!crtc || !crtc->state->mode_changed)
> + continue;
> +
> + funcs = crtc->helper_private;
> +
> + if (crtc->state->enable)
> + funcs->commit(crtc);
> + }
> +
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector *connector;
> + struct drm_encoder_helper_funcs *funcs;
> + struct drm_encoder *encoder;
> +
> + connector = old_state->connectors[i];
> +
> + if (!connector || !connector->state->best_encoder)
> + continue;
> +
> + encoder = connector->state->best_encoder;
> + funcs = encoder->helper_private;
> +
> + /*
> + * Each encoder has at most one connector (since we always steal
> + * it away), so we won't call call enable hooks twice.
> + */
> + if (encoder->bridge)
> + encoder->bridge->funcs->pre_enable(encoder->bridge);
> +
> + funcs->commit(encoder);
> +
> + if (encoder->bridge)
> + encoder->bridge->funcs->enable(encoder->bridge);
> + }
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
> +
> +static void
> +wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
> +{
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *old_crtc_state;
> + int ncrtcs = old_state->dev->mode_config.num_crtc;
> + int i, ret;
> +
> + for (i = 0; i < ncrtcs; i++) {
> + crtc = old_state->crtcs[i];
> + old_crtc_state = old_state->crtc_states[i];
> +
> + if (!crtc)
> + continue;
> +
> + /* No one cares about the old state, so abuse it for tracking
> + * and store whether we hold a vblank reference (and should do a
> + * vblank wait) in the ->enable boolean. */
> + old_crtc_state->enable = false;
> +
> + if (!crtc->state->enable)
> + continue;
> +
> + ret = drm_crtc_vblank_get(crtc);
> + if (ret != 0)
> + continue;
> +
> + old_crtc_state->enable = true;
> + old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);

I think you should collect last_vblank_count before drm_crtc_vblank_get

> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + crtc = old_state->crtcs[i];
> + old_crtc_state = old_state->crtc_states[i];
> +
> + if (!crtc || !old_crtc_state->enable)
> + continue;
> +
> + ret = wait_event_timeout(dev->vblank[i].queue,
> + old_crtc_state->last_vblank_count !=
> + drm_vblank_count(dev, i),
> + msecs_to_jiffies(50));
> +
> + drm_crtc_vblank_put(crtc);
> + }
> +}
> +
> +/**
> + * drm_atomic_helper_commit - commit validated state object
> + * @dev: DRM device
> + * @state: the driver state object
> + * @async: asynchronous commit
> + *
> + * This function commits a with drm_atomic_helper_check() pre-validated state
> + * object. This can still fail when e.g. the framebuffer reservation fails. For
> + * now this doesn't implement asynchronous commits.
> + *
> + * RETURNS
> + * Zero for success or -errno.
> + */
> +int drm_atomic_helper_commit(struct drm_device *dev,
> +     struct drm_atomic_state *state,
> +     bool async)
> +{
> + int ret;
> +
> + if (async)
> + return -EBUSY;
> +
> + ret = drm_atomic_helper_prepare_planes(dev, state);
> + if (ret)
> + return ret;
> +
> + /*
> + * This is the point of no return - everything below never fails except
> + * when the hw goes bonghits. Which means we can commit the new state on
> + * the software side now.
> + */
> +
> + drm_atomic_helper_swap_state(dev, state);
> +
> + /*
> + * Everything below can be run asynchronously withou the need to grab

s/withou/without/

> + * any modeset locks at all under one conditions: It must be guaranteed
> + * that the asynchronous work has either been cancelled (if the driver
> + * supports it, which at least requires that the framebuffers get
> + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
> + * before the new state gets committed on the software side with
> + * drm_atomic_helper_swap_state().
> + *
> + * This scheme allows new atomic state updates to be prepared and
> + * checked in parallel to the asynchronous completion of the previous
> + * update. Which is important since compositors need to figure out the
> + * composition of the next frame right after having submitted the
> + * current layout.
> + */
> +
> + drm_atomic_helper_commit_pre_planes(dev, state);
> +
> + drm_atomic_helper_commit_planes(dev, state);
> +
> + drm_atomic_helper_commit_post_planes(dev, state);
> +
> + wait_for_vblanks(dev, state);
> +
> + drm_atomic_helper_cleanup_planes(dev, state);
> +
> + drm_atomic_state_free(state);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_commit);
> +
>  /**
>   * drm_atomic_helper_prepare_planes - prepare plane resources after commit
>   * @dev: DRM device
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 95ecbb131053..46728a8ac622 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -927,6 +927,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
>
>   crtc_state->enable = true;
>   crtc_state->planes_changed = true;
> + crtc_state->mode_changed = true;
>   drm_mode_copy(&crtc_state->mode, mode);
>   drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
>
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 79938c62e7ad..9781ce739e10 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -30,6 +30,14 @@
>
>  int drm_atomic_helper_check(struct drm_device *dev,
>      struct drm_atomic_state *state);
> +int drm_atomic_helper_commit(struct drm_device *dev,
> +     struct drm_atomic_state *state,
> +     bool async);
> +
> +void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
> + struct drm_atomic_state *state);
> +void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
> +  struct drm_atomic_state *old_state);
>
>  int drm_atomic_helper_prepare_planes(struct drm_device *dev,
>       struct drm_atomic_state *state);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 77ff8992a3b7..ddff25eb34d4 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -229,6 +229,9 @@ struct drm_atomic_state;
>  /**
>   * struct drm_crtc_state - mutable crtc state
>   * @enable: whether the CRTC should be enabled, gates all other state
> + * @mode_changed: for use by helpers and drivers when computing state updates
> + * @last_vblank_count: for helpers and drivers to capture the vblank of the
> + * update to ensure framebuffer cleanup isn't done too early
>   * @planes_changed: for use by helpers and drivers when computing state updates
>   * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
>   * @mode: current mode timings
> @@ -241,6 +244,10 @@ struct drm_crtc_state {
>
>   /* computed state bits used by helpers and drivers */
>   bool planes_changed : 1;
> + bool mode_changed : 1;
> +
> + /* last_vblank_count: for vblank waits before cleanup */
> + u32 last_vblank_count;
>
>   /* adjusted_mode: for use by helpers and drivers */
>   struct drm_display_mode adjusted_mode;
> @@ -426,11 +433,14 @@ struct drm_crtc {
>  /**
>   * struct drm_connector_state - mutable connector state
>   * @crtc: crtc to connect connector to, NULL if disabled
> + * @best_encoder: can be used by helpers and drivers to select the encoder
>   * @state: backpointer to global drm_atomic_state
>   */
>  struct drm_connector_state {
>   struct drm_crtc *crtc;
>
> + struct drm_encoder *best_encoder;
> +
>   struct drm_atomic_state *state;
>  };
>
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-05 13:46     ` Daniel Vetter
@ 2014-11-05 19:48       ` Sean Paul
  2014-11-05 22:01         ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-05 19:48 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Intel Graphics Development, Daniel Thompson, DRI Development

On Wed, Nov 05, 2014 at 02:46:10PM +0100, Daniel Vetter wrote:
> Well, except page_flip since that requires async commit, which isn't
> there yet.
>
> For the functions which changes planes there's a bit of trickery
> involved to keep the fb refcounting working. But otherwise fairly
> straight-forward atomic updates.
>
> The property setting functions are still a bit incomplete. Once we
> have generic properties (e.g. rotation, but also all the properties
> needed by the atomic ioctl) we need to filter those out and parse them
> in the helper. Preferrably with the same function as used by the real
> atomic ioctl implementation.
>
> v2: Fixup kerneldoc, reported by Paulo.
>
> v3: Add missing EXPORT_SYMBOL.
>
> v4: We need to look at the crtc of the modeset, not some random
> leftover one from a previous loop when udpating the connector->crtc
> routing. Also push some local variables into inner loops to avoid
> these kinds of bugs.
>
> v5: Adjust semantics - drivers now own the atomic state upon
> successfully synchronous commit.
>
> v6: Use the set_crtc_for_plane function to assign the crtc, since
> otherwise the book-keeping is off.
>
> v7:
> - Improve comments.
> - Filter out the crtc of the ->set_config call when recomputing
>   crtc_state->enabled: We should compute the same state, but not doing
>   so will give us a good chance to catch bugs and inconsistencies -
>   the atomic helper's atomic_check function re-validates this again.
> - Fix the set_config implementation logic when disabling the crtc: We
>   still need to update the output routing to disable all the
>   connectors properly in the state. Caught by the atomic_check
>   functions, so at least that part worked ;-) Also add some WARN_ONs
>   to ensure ->set_config preconditions all apply.
>
> v8: Fixup an embarrassing h/vdisplay mixup.
>
> v9: Shuffled bad squash to the right patch, spotted by Daniel
>
> v10: Use set_crtc_for_connector as suggested by Sean.
>
> v11: Daniel Thompson noticed that my error handling is inconsistent
> and that in a few cases I didn't handle fatal errors (i.e. not
> -EDEADLK). Fix this by consolidate the ww mutex backoff handling
> into one check in the fail: block and flatten the error control
> flow everywhere else.
>
> Cc: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: Daniel Thompson <daniel.thompson@linaro.org>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Looks good to me, a couple nits.

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 504 +++++++++++++++++++++++++++++++++++-
>  include/drm/drm_atomic_helper.h     |  21 ++
>  2 files changed, 524 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 887e1971c915..b84581f8c8fc 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -86,6 +86,7 @@ steal_encoder(struct drm_atomic_state *state,
>   struct drm_crtc_state *crtc_state;
>   struct drm_connector *connector;
>   struct drm_connector_state *connector_state;
> + int ret;
>
>   /*
>   * We can only steal an encoder coming from a connector, which means we
> @@ -116,7 +117,9 @@ steal_encoder(struct drm_atomic_state *state,
>   if (IS_ERR(connector_state))
>   return PTR_ERR(connector_state);
>
> - connector_state->crtc = NULL;
> + ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
> + if (ret)
> + return ret;
>   connector_state->best_encoder = NULL;
>   }
>
> @@ -1045,3 +1048,502 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
>   }
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_swap_state);
> +
> +/**
> + * drm_atomic_helper_update_plane - Helper for primary plane update using atomic
> + * @plane: plane object to update
> + * @crtc: owning CRTC of owning plane
> + * @fb: framebuffer to flip onto plane
> + * @crtc_x: x offset of primary plane on crtc
> + * @crtc_y: y offset of primary plane on crtc
> + * @crtc_w: width of primary plane rectangle on crtc
> + * @crtc_h: height of primary plane rectangle on crtc
> + * @src_x: x offset of @fb for panning
> + * @src_y: y offset of @fb for panning
> + * @src_w: width of source rectangle in @fb
> + * @src_h: height of source rectangle in @fb
> + *
> + * Provides a default plane update handler using the atomic driver interface.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_atomic_helper_update_plane(struct drm_plane *plane,
> +   struct drm_crtc *crtc,
> +   struct drm_framebuffer *fb,
> +   int crtc_x, int crtc_y,
> +   unsigned int crtc_w, unsigned int crtc_h,
> +   uint32_t src_x, uint32_t src_y,
> +   uint32_t src_w, uint32_t src_h)
> +{
> + struct drm_atomic_state *state;
> + struct drm_plane_state *plane_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(plane->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> +retry:
> + plane_state = drm_atomic_get_plane_state(state, plane);
> + if (IS_ERR(plane_state)) {
> + ret = PTR_ERR(plane_state);
> + goto fail;
> + }
> +
> + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
> + if (ret != 0)
> + goto fail;
> + plane_state->fb = fb;
> + plane_state->crtc_x = crtc_x;
> + plane_state->crtc_y = crtc_y;
> + plane_state->crtc_h = crtc_h;
> + plane_state->crtc_w = crtc_w;
> + plane_state->src_x = src_x;
> + plane_state->src_y = src_y;
> + plane_state->src_h = src_h;
> + plane_state->src_w = src_w;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + /*
> + * Someone might have exchanged the framebuffer while we dropped locks
> + * in the backoff code. We need to fix up the fb refcount tracking the
> + * core does for us.
> + */
> + plane->old_fb = plane->fb;
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_update_plane);
> +
> +/**
> + * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic
> + * @plane: plane to disable
> + *
> + * Provides a default plane disablle handler using the atomic driver interface.

s/disablle/disable/

> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int drm_atomic_helper_disable_plane(struct drm_plane *plane)
> +{
> + struct drm_atomic_state *state;
> + struct drm_plane_state *plane_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(plane->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc);
> +retry:
> + plane_state = drm_atomic_get_plane_state(state, plane);
> + if (IS_ERR(plane_state)) {
> + ret = PTR_ERR(plane_state);
> + goto fail;
> + }
> +
> + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
> + if (ret != 0)
> + goto fail;
> + plane_state->fb = NULL;
> + plane_state->crtc_x = 0;
> + plane_state->crtc_y = 0;
> + plane_state->crtc_h = 0;
> + plane_state->crtc_w = 0;
> + plane_state->src_x = 0;
> + plane_state->src_y = 0;
> + plane_state->src_h = 0;
> + plane_state->src_w = 0;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + /*
> + * Someone might have exchanged the framebuffer while we dropped locks
> + * in the backoff code. We need to fix up the fb refcount tracking the
> + * core does for us.
> + */
> + plane->old_fb = plane->fb;
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_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_connector_state *conn_state;
> + int nconnectors = state->dev->mode_config.num_connector;
> + int ncrtcs = state->dev->mode_config.num_crtc;
> + int ret, i, j;
> +
> + ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
> +       state->acquire_ctx);
> + if (ret)
> + return ret;
> +
> + /* First grab all affected connector/crtc states. */
> + for (i = 0; i < set->num_connectors; i++) {
> + conn_state = drm_atomic_get_connector_state(state,
> +    set->connectors[i]);
> + if (IS_ERR(conn_state))
> + return PTR_ERR(conn_state);
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc *crtc = state->crtcs[i];
> +
> + if (!crtc)
> + continue;
> +
> + ret = drm_atomic_add_affected_connectors(state, crtc);
> + if (ret)
> + return ret;
> + }
> +
> + /* Then recompute connector->crtc links and crtc enabling state. */
> + for (i = 0; i < nconnectors; i++) {
> + struct drm_connector *connector;
> +
> + connector = state->connectors[i];
> + conn_state = state->connector_states[i];
> +
> + if (!connector)
> + continue;
> +
> + if (conn_state->crtc == set->crtc) {
> + ret = drm_atomic_set_crtc_for_connector(conn_state,
> + NULL);
> + if (ret)
> + return ret;
> + }
> +
> + for (j = 0; j < set->num_connectors; j++) {
> + if (set->connectors[j] == connector) {
> + ret = drm_atomic_set_crtc_for_connector(conn_state,
> + set->crtc);
> + if (ret)
> + return ret;
> + break;
> + }
> + }
> + }
> +
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc *crtc = state->crtcs[i];
> + struct drm_crtc_state *crtc_state = state->crtc_states[i];
> +
> + if (!crtc && crtc != set->crtc)

I think this should be an ||

> + continue;
> +
> + crtc_state->enable =
> + drm_atomic_connectors_for_crtc(state, crtc);
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * drm_atomic_helper_set_config - set a new config from userspace
> + * @set: mode set configuration
> + *
> + * Provides a default crtc set_config handler using the atomic driver interface.
> + *
> + * Returns:
> + * Returns 0 on success, negative errno numbers on failure.
> + */
> +int drm_atomic_helper_set_config(struct drm_mode_set *set)
> +{
> + struct drm_atomic_state *state;
> + struct drm_crtc *crtc = set->crtc;
> + struct drm_crtc_state *crtc_state;
> + struct drm_plane_state *primary_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(crtc->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> +retry:
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + if (IS_ERR(crtc_state)) {
> + ret = PTR_ERR(crtc_state);
> + goto fail;
> + }
> +
> + if (!set->mode) {
> + WARN_ON(set->fb);
> + WARN_ON(set->num_connectors);
> +
> + crtc_state->enable = false;
> + goto commit;
> + }
> +
> + WARN_ON(!set->fb);
> + WARN_ON(!set->num_connectors);
> +
> + crtc_state->enable = true;
> + drm_mode_copy(&crtc_state->mode, set->mode);
> +
> + primary_state = drm_atomic_get_plane_state(state, crtc->primary);
> + if (IS_ERR(primary_state)) {
> + ret = PTR_ERR(primary_state);
> + goto fail;
> + }
> +
> + ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> + if (ret != 0)
> + goto fail;
> + primary_state->fb = set->fb;
> + primary_state->crtc_x = 0;
> + primary_state->crtc_y = 0;
> + primary_state->crtc_h = set->mode->vdisplay;
> + primary_state->crtc_w = set->mode->hdisplay;
> + primary_state->src_x = set->x << 16;
> + primary_state->src_y = set->y << 16;
> + primary_state->src_h = set->mode->vdisplay << 16;
> + primary_state->src_w = set->mode->hdisplay << 16;
> +
> +commit:
> + ret = update_output_state(state, set);
> + if (ret)
> + goto fail;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + /*
> + * Someone might have exchanged the framebuffer while we dropped locks
> + * in the backoff code. We need to fix up the fb refcount tracking the
> + * core does for us.
> + */
> + crtc->primary->old_fb = crtc->primary->fb;
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_set_config);
> +
> +/**
> + * drm_atomic_helper_crtc_set_property - helper for crtc prorties
> + * @crtc: DRM crtc
> + * @property: DRM property
> + * @val: value of property
> + *
> + * Provides a default plane disablle handler using the atomic driver interface.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int
> +drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
> +    struct drm_property *property,
> +    uint64_t val)
> +{
> + struct drm_atomic_state *state;
> + struct drm_crtc_state *crtc_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(crtc->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + /* ->set_property is always called with all locks held. */
> + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
> +retry:
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + if (IS_ERR(crtc_state)) {
> + ret = PTR_ERR(crtc_state);
> + goto fail;
> + }
> +
> + ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
> +       property, val);
> + if (ret)
> + goto fail;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
> +
> +/**
> + * drm_atomic_helper_plane_set_property - helper for plane prorties
> + * @plane: DRM plane
> + * @property: DRM property
> + * @val: value of property
> + *
> + * Provides a default plane disable handler using the atomic driver interface.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int
> +drm_atomic_helper_plane_set_property(struct drm_plane *plane,
> +    struct drm_property *property,
> +    uint64_t val)
> +{
> + struct drm_atomic_state *state;
> + struct drm_plane_state *plane_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(plane->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + /* ->set_property is always called with all locks held. */
> + state->acquire_ctx = plane->dev->mode_config.acquire_ctx;
> +retry:
> + plane_state = drm_atomic_get_plane_state(state, plane);
> + if (IS_ERR(plane_state)) {
> + ret = PTR_ERR(plane_state);
> + goto fail;
> + }
> +
> + ret = plane->funcs->atomic_set_property(plane, plane_state,
> +       property, val);
> + if (ret)
> + goto fail;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
> +
> +/**
> + * drm_atomic_helper_connector_set_property - helper for connector prorties
> + * @connector: DRM connector
> + * @property: DRM property
> + * @val: value of property
> + *
> + * Provides a default plane disablle handler using the atomic driver interface.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure
> + */
> +int
> +drm_atomic_helper_connector_set_property(struct drm_connector *connector,
> +    struct drm_property *property,
> +    uint64_t val)
> +{
> + struct drm_atomic_state *state;
> + struct drm_connector_state *connector_state;
> + int ret = 0;
> +
> + state = drm_atomic_state_alloc(connector->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + /* ->set_property is always called with all locks held. */
> + state->acquire_ctx = connector->dev->mode_config.acquire_ctx;
> +retry:
> + connector_state = drm_atomic_get_connector_state(state, connector);
> + if (IS_ERR(connector_state)) {
> + ret = PTR_ERR(connector_state);
> + goto fail;
> + }
> +
> + ret = connector->funcs->atomic_set_property(connector, connector_state,
> +       property, val);
> + if (ret)
> + goto fail;
> +
> + ret = drm_atomic_commit(state);
> + if (ret != 0)
> + goto fail;
> +
> + /* Driver takes ownership of state on successful commit. */
> + return 0;
> +fail:
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 9781ce739e10..8cd6fe7a48e5 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -49,4 +49,25 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
>  void drm_atomic_helper_swap_state(struct drm_device *dev,
>    struct drm_atomic_state *state);
>
> +/* implementations for legacy interfaces */
> +int drm_atomic_helper_update_plane(struct drm_plane *plane,
> +   struct drm_crtc *crtc,
> +   struct drm_framebuffer *fb,
> +   int crtc_x, int crtc_y,
> +   unsigned int crtc_w, unsigned int crtc_h,
> +   uint32_t src_x, uint32_t src_y,
> +   uint32_t src_w, uint32_t src_h);
> +int drm_atomic_helper_disable_plane(struct drm_plane *plane);
> +int drm_atomic_helper_set_config(struct drm_mode_set *set);
> +
> +int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
> + struct drm_property *property,
> + uint64_t val);
> +int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
> + struct drm_property *property,
> + uint64_t val);
> +int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
> + struct drm_property *property,
> + uint64_t val);
> +
>  #endif /* DRM_ATOMIC_HELPER_H_ */
> --
> 2.1.1
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces
  2014-11-05 18:53   ` Sean Paul
@ 2014-11-05 21:44     ` Daniel Vetter
  2014-11-06 18:28       ` Sean Paul
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 21:44 UTC (permalink / raw)
  To: Sean Paul; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

I've applied all the other nits, replies to the more interesting bits
below.

On Wed, Nov 05, 2014 at 01:53:48PM -0500, Sean Paul wrote:
> On Sun, Nov 02, 2014 at 02:19:23PM +0100, Daniel Vetter wrote:
> > + if (new_encoder != connector_state->best_encoder) {
> 
> nit: If you just returned early when the encoder doesn't change, you can save
> indentation and line breaks.

Hm, that would mean either a goto (I don't like that for non-exceptional
control flow) or duplicating the debug output. I'll go with the latter and
frob it a bit.

> > + return ret;
> > +
> > + has_connectors = drm_atomic_connectors_for_crtc(state,
> > + crtc);
> > +
> > + if (crtc_state->enable != has_connectors) {
> 
> This makes me a little nervous. Even though has_connectors is a bool,
> drm_atomic_connectors_for_crtc returns an int, and this seems like something
> that someone might "fix" in the future.
> 
> [PATCH] drm/atomic: Use proper type for drm_atomic_connectors_for_crtc

Hm, yeah. I'll rename to num_connectors and add a !!. The idea of
returning an int and not just a bool is that drivers might care if there's
more than one, i.e. for cloned setups. At least i915 has some special
considerations for that in some cases.


> > + ret = drm_crtc_vblank_get(crtc);
> > + if (ret != 0)
> > + continue;
> > +
> > + old_crtc_state->enable = true;
> > + old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);
> 
> I think you should collect last_vblank_count before drm_crtc_vblank_get

vblank_get should block on anything, and I'm not sure whether the
drm_vblank_count can't just fall over if vblank_get fails (since
vblank_get before vblank_count is the pattern drm_irq.c uses iirc). So I'd
prefer it this way round just for paranoia. So I think I'll stick with
this scheme. The waiting is only done once we've grabbed all the vblank
count, and that's the important part to ensure we don't wait for too long.

This really is just all part of the "generic code has no idea about the
dpms state of a crtc". I'll plan to fix that with the missing dpms on
atomic pieces.
-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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-05 19:48       ` Sean Paul
@ 2014-11-05 22:01         ` Daniel Vetter
  2014-11-06 18:31           ` Sean Paul
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-05 22:01 UTC (permalink / raw)
  To: Sean Paul
  Cc: Daniel Vetter, Intel Graphics Development, Daniel Thompson,
	DRI Development

On Wed, Nov 05, 2014 at 02:48:48PM -0500, Sean Paul wrote:
> > + if (!crtc && crtc != set->crtc)
> 
> I think this should be an ||

Hm. My idea idea was actually something along the lines of
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 4f80885de3f6..077c792c46e0 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1271,7 +1271,14 @@ static int update_output_state(struct drm_atomic_state *state,
 		struct drm_crtc *crtc = state->crtcs[i];
 		struct drm_crtc_state *crtc_state = state->crtc_states[i];
 
-		if (!crtc && crtc != set->crtc)
+		if (!crtc)
+			continue;
+
+		/* 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;
 
 		crtc_state->enable =


I.e. that we don't recompute the new enable state for set->crtc so that we
can catch bug in the helper function or core drm code which maps the
legacy ->set_config to the atomic interface.

Still r-b with that change applied, or want to take a deeper look again?
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [Intel-gfx] [PATCH 12/17] drm/atomic: Integrate fence support
  2014-11-02 13:19 ` [PATCH 12/17] drm/atomic: Integrate fence support Daniel Vetter
@ 2014-11-06 17:43   ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:43 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:25PM +0100, Daniel Vetter wrote:
> This patch is for enabling async commits. It replaces an earlier
> approach which added an async boolean paramter to the ->prepare_fb
> callbacks. The idea is that prepare_fb picks up the right fence to
> synchronize against, which is then used by the synchronous commit
> helper. For async commits drivers can either register a callback to
> the fence or simply do the synchronous wait in their async work queue.
>
> v2: Remove unused variable.
>
> v3: Only wait for fences after the point of no return in the part
> of the commit function which can be run asynchronously. This is after
> the atomic state has been swapped in, hence now check
> plane->state->fence.
>
> Also add a WARN_ON to make sure we don't try to wait on a fence when
> there's no fb, just as a sanity check.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 23 +++++++++++++++++++++++
>  include/drm/drm_crtc.h              |  3 +++
>  2 files changed, 26 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 26fe60356a0f..afdc376aa7e7 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -30,6 +30,7 @@
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <linux/fence.h>
>
>  static void
>  drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
> @@ -704,6 +705,26 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes);
>
> +static void wait_for_fences(struct drm_device *dev,
> +    struct drm_atomic_state *state)
> +{
> + int nplanes = dev->mode_config.num_total_plane;
> + int i;
> +
> + for (i = 0; i < nplanes; i++) {
> + struct drm_plane *plane = state->planes[i];
> +
> + if (!plane || !plane->state->fence)
> + continue;
> +
> + WARN_ON(!plane->state->fb);
> +
> + fence_wait(plane->state->fence, false);
> + fence_put(plane->state->fence);
> + plane->state->fence = NULL;
> + }
> +}
> +
>  static void
>  wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
>  {
> @@ -801,6 +822,8 @@ int drm_atomic_helper_commit(struct drm_device *dev,
>   * current layout.
>   */
>
> + wait_for_fences(dev, state);
> +
>   drm_atomic_helper_commit_pre_planes(dev, state);
>
>   drm_atomic_helper_commit_planes(dev, state);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index ddff25eb34d4..5c34665ebb9d 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -42,6 +42,7 @@ struct drm_object_properties;
>  struct drm_file;
>  struct drm_clip_rect;
>  struct device_node;
> +struct fence;
>
>  #define DRM_MODE_OBJECT_CRTC 0xcccccccc
>  #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
> @@ -659,6 +660,7 @@ struct drm_connector {
>   * struct drm_plane_state - mutable plane state
>   * @crtc: currently bound CRTC, NULL if disabled
>   * @fb: currently bound fb
> + * @fence: optional fence to wait for before scanning out @fb
>   * @crtc_x: left position of visible portion of plane on crtc
>   * @crtc_y: upper position of visible portion of plane on crtc
>   * @crtc_w: width of visible portion of plane on crtc
> @@ -674,6 +676,7 @@ struct drm_connector {
>  struct drm_plane_state {
>   struct drm_crtc *crtc;
>   struct drm_framebuffer *fb;
> + struct fence *fence;
>
>   /* Signed dest location allows it to be partially off screen */
>   int32_t crtc_x, crtc_y;
> --
> 2.1.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 13/17] drm/atomic-helpers: document how to implement async commit
  2014-11-02 13:19 ` [PATCH 13/17] drm/atomic-helpers: document how to implement async commit Daniel Vetter
@ 2014-11-06 17:43   ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:43 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:26PM +0100, Daniel Vetter wrote:
> No helper function to do it all yet provided since no driver has
> support for driver core fences yet. Which we'd need to make the
> implementation really generic.
>
> v2: Clarify async howto a bit per the discussion With Rob Clark.
>
> Cc: Rob Clark <robdclark@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 38 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index afdc376aa7e7..92ae34bde44d 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -841,6 +841,44 @@ int drm_atomic_helper_commit(struct drm_device *dev,
>  EXPORT_SYMBOL(drm_atomic_helper_commit);
>
>  /**
> + * DOC: implementing async commit
> + *
> + * For now the atomic helpers don't support async commit directly. If there is
> + * real need it could be added though, using the dma-buf fence infrastructure
> + * for generic synchronization with outstanding rendering.
> + *
> + * For now drivers have to implement async commit themselves, with the following
> + * sequence being the recommended one:
> + *
> + * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function
> + * which commit needs to call which can fail, so we want to run it first and
> + * synchronously.
> + *
> + * 2. Synchronize with any outstanding asynchronous commit worker threads which
> + * might be affected the new state update. This can be done by either cancelling
> + * or flushing the work items, depending upon whether the driver can deal with
> + * cancelled updates. Note that it is important to ensure that the framebuffer
> + * cleanup is still done when cancelling.
> + *
> + * For sufficient parallelism it is recommended to have a work item per crtc
> + * (for updates which don't touch global state) and a global one. Then we only
> + * need to synchronize with the crtc work items for changed crtcs and the global
> + * work item, which allows nice concurrent updates on disjoint sets of crtcs.
> + *
> + * 3. The software state is updated synchronously with
> + * drm_atomic_helper_swap_state. Doing this under the protection of all modeset
> + * locks means concurrent callers never see inconsistent state. And doing this
> + * while it's guaranteed that no relevant async worker runs means that async
> + * workers do not need grab any locks. Actually they must not grab locks, for
> + * otherwise the work flushing will deadlock.
> + *
> + * 4. Schedule a work item to do all subsequent steps, using the split-out
> + * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and
> + * then cleaning up the framebuffers after the old framebuffer is no longer
> + * being displayed.
> + */
> +
> +/**
>   * drm_atomic_helper_prepare_planes - prepare plane resources after commit
>   * @dev: DRM device
>   * @state: atomic state object with old state structures
> --
> 2.1.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 14/17] drm/atomic-helper: implement ->page_flip
  2014-11-02 13:19 ` [PATCH 14/17] drm/atomic-helper: implement ->page_flip Daniel Vetter
  2014-11-04 22:09   ` [PATCH] " Daniel Vetter
@ 2014-11-06 17:43   ` Sean Paul
  2014-11-06 18:13     ` Daniel Vetter
  1 sibling, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:43 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:27PM +0100, Daniel Vetter wrote:
> Currently there is no way to implement async flips using atomic, that
> essentially requires us to be able to cancel pending requests
> mid-flight.
>
> To be able to do that (and I guess we want this since vblank synced
> updates whic opportunistically cancel still pending updates seem to be

s/whic/which/

> wanted) we'd need to add a mandatory cancellation mode. Depending upon
> the exact semantics we decide upon that could mean that userspace will
> not get completion events, or will get them all stacked up.
>
> So reject async updates for now. Also async updates usually means not
> vblank synced at all, and I guess for drivers which want to support
> this they should simply add a special pageflip handler (since usually
> you need a special flip cmd to achieve this). That kind of async flip
> is pretty much exclusively just used for games and benchmarks where
> dropping just one frame means you'll get a headshot or something bad
> like that ... And so slight amounts of tearing is acceptable.
>
> v2: Fixup kerneldoc, reported by Paulo.
>
> v3: Use the set_crtc_for_plane function to assign the crtc, since
> otherwise the book-keeping is off.
>
> v4: Update crtc->primary->fb since ->page_flip is the only driver
> callback where the core won't do this itself. We might want to fix
> this inconsistency eventually.
>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Minor nit regarding error handing, either way:

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 90 +++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic_helper.h     |  5 +++
>  2 files changed, 95 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 92ae34bde44d..70bd67cf86e3 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1617,3 +1617,93 @@ backoff:
>   goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
> +
> +/**
> + * drm_atomic_helper_page_flip - execute a legacy page flip
> + * @crtc: DRM crtc
> + * @fb: DRM framebuffer
> + * @event: optional DRM event to signal upon completion
> + * @flags: flip flags for non-vblank sync'ed updates
> + *
> + * Provides a default page flip implementation using the atomic driver interface.
> + *
> + * Note that for now so called async page flips (i.e. updates which are not
> + * synchronized to vblank) are not supported, since the atomic interfaces have
> + * no provisions for this yet.
> + *
> + * Returns:
> + * Returns 0 on success, negative errno numbers on failure.
> + */
> +int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
> + struct drm_framebuffer *fb,
> + struct drm_pending_vblank_event *event,
> + uint32_t flags)
> +{
> + struct drm_plane *plane = crtc->primary;
> + struct drm_atomic_state *state;
> + struct drm_plane_state *plane_state;
> + struct drm_crtc_state *crtc_state;
> + int ret = 0;
> +
> + if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
> + return -EINVAL;
> +
> + state = drm_atomic_state_alloc(plane->dev);
> + if (!state)
> + return -ENOMEM;
> +
> + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> +retry:
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + if (IS_ERR(crtc_state)) {
> + ret = PTR_ERR(crtc_state);
> + if (ret == -EDEADLK)
> + goto backoff;
> + else
> + goto fail;

This function would benefit from the error cleanup you did in the previous
patch (ie, doing the -EDEADLK check in fail and punting to backoff there).

> + }
> + crtc_state->event = event;
> +
> + plane_state = drm_atomic_get_plane_state(state, plane);
> + if (IS_ERR(plane_state)) {
> + ret = PTR_ERR(plane_state);
> + if (ret == -EDEADLK)
> + goto backoff;
> + else
> + goto fail;
> + }
> +
> + drm_atomic_set_crtc_for_plane(plane_state, crtc);
> + plane_state->fb = fb;
> +
> + ret = drm_atomic_async_commit(state);
> + if (ret == -EDEADLK)
> + goto backoff;
> +
> + /* Driver takes ownership of state on successful async commit. */
> + if (ret == 0) {
> + /* TODO: ->page_flip is the only driver callback where the core
> + * doesn't update plane->fb. For now patch it up here. */
> + plane->fb = plane->state->fb;
> +
> + return 0;
> + }
> +
> +fail:
> + drm_atomic_state_free(state);
> +
> + return ret;
> +backoff:
> + drm_atomic_legacy_backoff(state);
> + drm_atomic_state_clear(state);
> +
> + /*
> + * Someone might have exchanged the framebuffer while we dropped locks
> + * in the backoff code. We need to fix up the fb refcount tracking the
> + * core does for us.
> + */
> + plane->old_fb = plane->fb;
> +
> + goto retry;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_page_flip);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 8cd6fe7a48e5..28a2f3a815fd 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
>  int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
>   struct drm_property *property,
>   uint64_t val);
> +int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
> + struct drm_framebuffer *fb,
> + struct drm_pending_vblank_event *event,
> + uint32_t flags);
> +
>
>  #endif /* DRM_ATOMIC_HELPER_H_ */
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
  2014-11-03 14:45   ` Daniel Thompson
@ 2014-11-06 17:43   ` Sean Paul
  2014-11-06 19:57     ` Daniel Vetter
  2014-11-06 19:55   ` [PATCH] " Daniel Vetter
  2 siblings, 1 reply; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:43 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:28PM +0100, Daniel Vetter wrote:
> The atomic users and helpers assume that there is always a obj->state
> structure around. Which means drivers need to somehow create that at
> driver load time. Also it should obviously reset hardware state, so
> needs to be reset upon resume.
>
> Finally the destroy/duplicate_state functions are an awful lot of
> boilerplate if the driver doesn't need anything beyond the default
> state objects.
>
> So add helper functions for all of this.
>
> v2: Somehow the plane/connector versions got lost in the first
> version.
>
> v3: Add kerneldoc.
>
> v4: Make duplicate_state functions a bit more robust, which is useful
> for debugging state tracking issues when transitioning to atomic.
>
> v5: Clear temporary variables in the crtc state when duplicating it,
> like ->mode_changed or ->planes_changed. If we don't do this stale
> values for these might pollute the next atomic modeset.
>
> v6: Also clear crtc_state->event in case the driver didn't (yet) clear
> this out.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Minus the fixup nits that danielt pointed out

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 154 +++++++++++++++++++++++++++++++++++-
>  include/drm/drm_atomic_helper.h     |  19 +++++
>  2 files changed, 170 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 70bd67cf86e3..bd38df3cbe55 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1429,7 +1429,7 @@ EXPORT_SYMBOL(drm_atomic_helper_set_config);
>  /**
>   * drm_atomic_helper_crtc_set_property - helper for crtc prorties
>   * @crtc: DRM crtc
> - * @prorty: DRM property
> + * @property: DRM property
>   * @val: value of property
>   *
>   * Provides a default plane disablle handler using the atomic driver interface.
> @@ -1493,7 +1493,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
>  /**
>   * drm_atomic_helper_plane_set_property - helper for plane prorties
>   * @plane: DRM plane
> - * @prorty: DRM property
> + * @property: DRM property
>   * @val: value of property
>   *
>   * Provides a default plane disable handler using the atomic driver interface.
> @@ -1557,7 +1557,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
>  /**
>   * drm_atomic_helper_connector_set_property - helper for connector prorties
>   * @connector: DRM connector
> - * @prorty: DRM property
> + * @property: DRM property
>   * @val: value of property
>   *
>   * Provides a default plane disablle handler using the atomic driver interface.
> @@ -1707,3 +1707,151 @@ backoff:
>   goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_page_flip);
> +
> +/**
> + * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
> + * @crtc: drm CRTC
> + *
> + * Resets the atomic state for @crtc by freeing the state pointer and allocating
> + * a new empty state object.
> + */
> +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
> +{
> + kfree(crtc->state);
> + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
> +
> +/**
> + * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
> + * @crtc: drm CRTC
> + *
> + * Default CRTC state duplicate hook for drivers which don't have their own
> + * subclassed CRTC state structure.
> + */
> +struct drm_crtc_state *
> +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
> +{
> + struct drm_crtc_state *state;
> +
> + if (WARN_ON(!crtc->state))
> + return NULL;
> +
> + state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
> +
> + if (state) {
> + state->mode_changed = false;
> + state->planes_changed = false;
> + state->event = NULL;
> + }
> +
> + return state;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_crtc_destroy_state - default state destroy hook
> + * @crtc: drm CRTC
> + * @state: CRTC state object to release
> + *
> + * Default CRTC state destroy hook for drivers which don't have their own
> + * subclassed CRTC state structure.
> + */
> +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
> +  struct drm_crtc_state *state)
> +{
> + kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
> +
> +/**
> + * drm_atomic_helper_plane_reset - default ->reset hook for planes
> + * @plane: drm plane
> + *
> + * Resets the atomic state for @plane by freeing the state pointer and
> + * allocating a new empty state object.
> + */
> +void drm_atomic_helper_plane_reset(struct drm_plane *plane)
> +{
> + kfree(plane->state);
> + plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
> +
> +/**
> + * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
> + * @plane: drm plane
> + *
> + * Default plane state duplicate hook for drivers which don't have their own
> + * subclassed plane state structure.
> + */
> +struct drm_plane_state *
> +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
> +{
> + if (WARN_ON(!plane->state))
> + return NULL;
> +
> + return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_plane_destroy_state - default state destroy hook
> + * @plane: drm plane
> + * @state: plane state object to release
> + *
> + * Default plane state destroy hook for drivers which don't have their own
> + * subclassed plane state structure.
> + */
> +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
> +  struct drm_plane_state *state)
> +{
> + kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
> +
> +/**
> + * drm_atomic_helper_connector_reset - default ->reset hook for connectors
> + * @connector: drm connector
> + *
> + * Resets the atomic state for @connector by freeing the state pointer and
> + * allocating a new empty state object.
> + */
> +void drm_atomic_helper_connector_reset(struct drm_connector *connector)
> +{
> + kfree(connector->state);
> + connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
> +
> +/**
> + * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
> + * @connector: drm connector
> + *
> + * Default connector state duplicate hook for drivers which don't have their own
> + * subclassed connector state structure.
> + */
> +struct drm_connector_state *
> +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
> +{
> + if (WARN_ON(!connector->state))
> + return NULL;
> +
> + return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
> +
> +/**
> + * drm_atomic_helper_connector_destroy_state - default state destroy hook
> + * @connector: drm connector
> + * @state: connector state object to release
> + *
> + * Default connector state destroy hook for drivers which don't have their own
> + * subclassed connector state structure.
> + */
> +void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> +  struct drm_connector_state *state)
> +{
> + kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 28a2f3a815fd..67e3c4645ae0 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -74,5 +74,24 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
>   struct drm_pending_vblank_event *event,
>   uint32_t flags);
>
> +/* default implementations for state handling */
> +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
> +struct drm_crtc_state *
> +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
> +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
> +  struct drm_crtc_state *state);
> +
> +void drm_atomic_helper_plane_reset(struct drm_plane *plane);
> +struct drm_plane_state *
> +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
> +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
> +  struct drm_plane_state *state);
> +
> +void drm_atomic_helper_connector_reset(struct drm_connector *connector);
> +struct drm_connector_state *
> +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
> +void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> +  struct drm_connector_state *state);
> +
>
>  #endif /* DRM_ATOMIC_HELPER_H_ */
> --
> 2.1.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers
  2014-11-02 13:19 ` [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers Daniel Vetter
@ 2014-11-06 17:43   ` Sean Paul
  2014-11-06 20:00   ` [PATCH] " Daniel Vetter
  1 sibling, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:43 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:29PM +0100, Daniel Vetter wrote:
> In all cases the text requires that new drivers are converted to the
> atomic interfaces.
>
> v2: Add overview for state handling.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  Documentation/DocBook/drm.tmpl      | 20 +++++++++++++++++++-
>  drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_helper.c   | 20 ++++++++++++++++++++
>  drivers/gpu/drm/drm_plane_helper.c  | 26 +++++++++++++++++++++++++-
>  4 files changed, 100 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index ea0ef43b19e1..5e3a11f5e941 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -2324,8 +2324,25 @@ void intel_crt_init(struct drm_device *dev)
>        </itemizedlist>
>      </sect2>
>      <sect2>
> +      <title>Atomic Modeset Helper Functions Reference</title>
> +      <sect3>
> + <title>Overview</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c overview
> +      </sect3>
> +      <sect3>
> + <title>Implementing Asynchronous Atomic Commit</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c implementing async commit
> +      </sect3>
> +      <sect3>
> + <title>Atomic State Reset and Initialization</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
> +      </sect3>
> +!Edrivers/gpu/drm/drm_atomic_helper.c
> +    </sect2>
> +    <sect2>
>        <title>Modeset Helper Functions Reference</title>
>  !Edrivers/gpu/drm/drm_crtc_helper.c
> +!Pdrivers/gpu/drm/drm_crtc_helper.c overview
>      </sect2>
>      <sect2>
>        <title>Output Probing Helper Functions Reference</title>
> @@ -2379,7 +2396,8 @@ void intel_crt_init(struct drm_device *dev)
>      </sect2>
>      <sect2>
>        <title id="drm-kms-planehelpers">Plane Helper Reference</title>
> -!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
> +!Edrivers/gpu/drm/drm_plane_helper.c
> +!Pdrivers/gpu/drm/drm_plane_helper.c overview
>      </sect2>
>    </sect1>
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index bd38df3cbe55..d0ca681d6326 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -32,6 +32,27 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <linux/fence.h>
>
> +/**
> + * DOC: overview
> + *
> + * This helper library provides implementations of check and commit functions on
> + * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
> + * also provides convenience implementations for the atomic state handling
> + * callbacks for drivers which don't need to subclass the drm core structures to
> + * add their own additional internal state.
> + *
> + * This library also provides default implementations for the check callback in
> + * drm_atomic_helper_check and for the commit callback with
> + * drm_atomic_helper_commit. But the individual stages and callbacks are expose
> + * to allow drivers to mix and match and e.g. use the plane helpers only
> + * together with a driver private modeset implementation.
> + *
> + * This library also provides implementations for all the legacy driver
> + * interfaces on top of the atomic interface. See drm_atomic_helper_set_config,
> + * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the
> + * various functions to implement set_property callbacks. New drivers must not
> + * implement these functions themselves but must use the provided helpers.
> + */
>  static void
>  drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
>   struct drm_plane_state *plane_state,
> @@ -1709,6 +1730,21 @@ backoff:
>  EXPORT_SYMBOL(drm_atomic_helper_page_flip);
>
>  /**
> + * DOC: atomic state reset and initialization
> + *
> + * Both the drm core and the atomic helpers assume that there is always the full
> + * and correct atomic software state for all connectors, CRTCs and planes
> + * available. Which is a bit a problem on driver load and also after system
> + * suspend. One way to solve this is to have a hardware state read-out
> + * infrastructure which reconstructs the full software state (e.g. the i915
> + * driver).
> + *
> + * The simpler solution is to just reset the software state to everything off,
> + * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
> + * the atomic helpers provide default reset implementations for all hooks.
> + */
> +
> +/**
>   * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
>   * @crtc: drm CRTC
>   *
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 46728a8ac622..33195e9adaab 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -41,6 +41,26 @@
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_edid.h>
>
> +/**
> + * DOC: overview
> + *
> + * The CRTC modeset helper library provides a default set_config implementation
> + * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
> + * the same callbacks which drivers can use to e.g. restore the modeset
> + * configuration on resume with drm_helper_resume_force_mode().
> + *
> + * The driver callbacks are mostly compatible with the atomic modeset helpers,
> + * except for the handling of the primary plane: Atomic helpers require that the
> + * primary plane is implemented as a real standalone plane and not directly tied
> + * to the CRTC state. For easier transition this library provides functions to
> + * implement the old semantics required by the CRTC helpers using the new plane
> + * and atomic helper callbacks.
> + *
> + * Drivers are strongly urged to convert to the atomic helpers (by way of first
> + * converting to the plane helpers). New drivers must not use these functions
> + * but need to implement the atomic interface instead, potentially using the
> + * atomic helpers for that.
> + */
>  MODULE_AUTHOR("David Airlie, Jesse Barnes");
>  MODULE_DESCRIPTION("DRM KMS helper");
>  MODULE_LICENSE("GPL and additional rights");
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> index 40ecb2c6e858..df69522b1f0e 100644
> --- a/drivers/gpu/drm/drm_plane_helper.c
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -31,6 +31,31 @@
>
>  #define SUBPIXEL_MASK 0xffff
>
> +/**
> + * DOC: overview
> + *
> + * This helper library has two ports. The first part has support to implement

s/ports/parts/

> + * primary plane support on top of the normal CRTC configuration interface. Sinc

s/Sinc/Since/

> + * the legacy ->set_config interface ties the primary plane together with the
> + * CRTC state this does not userspace to disable the primary plane itself. To

s/does not/does not allow/

> + * avoid too much duplicated code use drm_plane_helper_check_update() which can
> + * be used to enforce the same restrictions as primary planes had thus. The
> + * default primary plane only expose XRBG8888 and ARGB8888 as valid pixel
> + * formats for the attached framebuffer.
> + *
> + * Drivers are highly recommended to implement proper support for primary
> + * planes, and newly merged drivers must not rely upon these transitional
> + * helpers.
> + *
> + * The second part also implements transitional helpers which allow drivers to
> + * gradually switch to the atomic helper infrastructure for plane updates. Once
> + * that switch is complete drivers shouldn't use these any longer, instead using
> + * the proper legacy implementations for update and disable plane hooks provided
> + * by the atomic helpers.
> + *
> + * Again drivers are strongly urged to switch to the new interfaces.
> + */
> +
>  /*
>   * This is the minimal list of formats that seem to be safe for modeset use
>   * with all current DRM drivers.  Most hardware can actually support more
> @@ -40,7 +65,6 @@
>   */
>  static const uint32_t safe_modeset_formats[] = {
>   DRM_FORMAT_XRGB8888,
> - DRM_FORMAT_ARGB8888,

Whoops!

>  };
>
>  /*
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb
  2014-11-02 13:19 ` [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb Daniel Vetter
  2014-11-04 21:57   ` [PATCH] " Daniel Vetter
@ 2014-11-06 17:44   ` Sean Paul
  1 sibling, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 17:44 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Sun, Nov 02, 2014 at 02:19:30PM +0100, Daniel Vetter wrote:
> So my original plan was that the drm core refcounts framebuffers like
> with the legacy ioctls. But that doesn't work for a bunch of reasons:
>
> - State objects might live longer than until the next fb change
>   happens for a plane. For example delayed cleanup work only happens
>   _after_ the pageflip ioctl has completed. So this definitely doesn't
>   work without the plane state holding its own refernces.

s/refernces/references/

>
> - The other issue is transition from legacy to atomic implementations,
>   where the driver works under a mix of both worlds. Which means
>   legacy paths might not properly update the ->fb pointer under
>   plane->state->fb. Which is a bit a problem when then someone comes
>   around and _does_ try to clean it up when it's long gone.
>
> The second issue is just a bit a transition bug, since drivers should
> update plane->state->fb in all the paths that aren't converted yet.
> But a bit more robustness for the transition cant' hurt - we pull

s/cant'/can't/

> similar tricks with cleaning up the old fb in the transitional helpers
> already.
>
> The pattern for drivers that transition is
>
> if (plane->state)
> drm_atomic_set_fb_for_plane(plane->state, plane->fb);
>
> inserted after the fb update has logically completed at the end of
> ->set_config (or ->set_base/mode_set if using the crtc helpers),
> ->page_flip, ->update_plane or any other entry point which updates
> plane->fb.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/drm_atomic.c        | 27 +++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++++++++++------
>  drivers/gpu/drm/drm_crtc_helper.c   |  7 ++++---
>  drivers/gpu/drm/drm_plane_helper.c  | 14 +++++++-------
>  include/drm/drm_atomic.h            |  2 ++
>  5 files changed, 59 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index c6db8a48cad6..af34321b675d 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -366,6 +366,33 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
>  EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
>
>  /**
> + * drm_atomic_set_fb_for_plane - set crtc for plane
> + * @plane_state: atomic state object for the plane
> + * @fb: fb to use for the plane
> + *
> + * Changing the assigned crtc for a plane requires us to grab the lock and state
> + * for the new crtc, as needed. This function takes care of all these details
> + * besides updating the pointer in the state object itself.
> + */
> +void
> +drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
> +    struct drm_framebuffer *fb)
> +{
> + if (plane_state->fb)
> + drm_framebuffer_unreference(plane_state->fb);
> + if (fb)
> + drm_framebuffer_reference(fb);
> + plane_state->fb = fb;
> +
> + if (fb)
> + DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n",
> +      fb->base.id, plane_state);
> + else
> + DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state);
> +}
> +EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
> +
> +/**
>   * drm_atomic_set_crtc_for_connector - set crtc for connector
>   * @conn_state: atomic state object for the connector
>   * @crtc: crtc to use for the connector
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index d0ca681d6326..a5de60faedff 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1175,7 +1175,7 @@ retry:
>   }
>
>   drm_atomic_set_crtc_for_plane(plane_state, crtc);
> - plane_state->fb = fb;
> + drm_atomic_set_fb_for_plane(plane_state, fb);
>   plane_state->crtc_x = crtc_x;
>   plane_state->crtc_y = crtc_y;
>   plane_state->crtc_h = crtc_h;
> @@ -1242,7 +1242,7 @@ retry:
>   }
>
>   drm_atomic_set_crtc_for_plane(plane_state, NULL);
> - plane_state->fb = NULL;
> + drm_atomic_set_fb_for_plane(plane_state, NULL);
>   plane_state->crtc_x = 0;
>   plane_state->crtc_y = 0;
>   plane_state->crtc_h = 0;
> @@ -1402,7 +1402,7 @@ retry:
>   }
>
>   drm_atomic_set_crtc_for_plane(primary_state, crtc);
> - primary_state->fb = set->fb;
> + drm_atomic_set_fb_for_plane(primary_state, set->fb);
>   primary_state->crtc_x = 0;
>   primary_state->crtc_y = 0;
>   primary_state->crtc_h = set->mode->vdisplay;
> @@ -1695,7 +1695,7 @@ retry:
>   }
>
>   drm_atomic_set_crtc_for_plane(plane_state, crtc);
> - plane_state->fb = fb;
> + drm_atomic_set_fb_for_plane(plane_state, fb);
>
>   ret = drm_atomic_async_commit(state);
>   if (ret == -EDEADLK)
> @@ -1809,6 +1809,9 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
>   */
>  void drm_atomic_helper_plane_reset(struct drm_plane *plane)
>  {
> + if (plane->state && plane->state->fb)
> + drm_framebuffer_unreference(plane->state->fb);
> +
>   kfree(plane->state);
>   plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
>  }
> @@ -1824,10 +1827,17 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
>  struct drm_plane_state *
>  drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
>  {
> + struct drm_plane_state *state;
> +
>   if (WARN_ON(!plane->state))
>   return NULL;
>
> - return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
> + state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
> +
> + if (state && state->fb)
> + drm_framebuffer_reference(state->fb);
> +
> + return state;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
>
> @@ -1840,8 +1850,11 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
>   * subclassed plane state structure.
>   */
>  void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
> -  struct drm_plane_state *state)
> +   struct drm_plane_state *state)
>  {
> + if (state->fb)
> + drm_framebuffer_unreference(state->fb);
> +
>   kfree(state);
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 33195e9adaab..d552708409de 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -34,11 +34,13 @@
>  #include <linux/moduleparam.h>
>
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_fourcc.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_plane_helper.h>
> +#include <drm/drm_atomic_helper.h>
>  #include <drm/drm_edid.h>
>
>  /**
> @@ -998,15 +1000,14 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
>   if (plane->funcs->atomic_duplicate_state)
>   plane_state = plane->funcs->atomic_duplicate_state(plane);
>   else if (plane->state)
> - plane_state = kmemdup(plane->state, sizeof(*plane_state),
> -      GFP_KERNEL);
> + plane_state = drm_atomic_helper_plane_duplicate_state(plane);
>   else
>   plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
>   if (!plane_state)
>   return -ENOMEM;
>
>   plane_state->crtc = crtc;
> - plane_state->fb = crtc->primary->fb;
> + drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
>   plane_state->crtc_x = 0;
>   plane_state->crtc_y = 0;
>   plane_state->crtc_h = crtc->mode.vdisplay;
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> index df69522b1f0e..497104df112b 100644
> --- a/drivers/gpu/drm/drm_plane_helper.c
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -27,7 +27,9 @@
>  #include <drm/drmP.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_rect.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
>
>  #define SUBPIXEL_MASK 0xffff
>
> @@ -462,7 +464,7 @@ fail:
>   if (plane->funcs->atomic_destroy_state)
>   plane->funcs->atomic_destroy_state(plane, plane_state);
>   else
> - kfree(plane_state);
> + drm_atomic_helper_plane_destroy_state(plane, plane_state);
>   }
>
>   return ret;
> @@ -503,15 +505,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
>   if (plane->funcs->atomic_duplicate_state)
>   plane_state = plane->funcs->atomic_duplicate_state(plane);
>   else if (plane->state)
> - plane_state = kmemdup(plane->state, sizeof(*plane_state),
> -      GFP_KERNEL);
> + plane_state = drm_atomic_helper_plane_duplicate_state(plane);
>   else
>   plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
>   if (!plane_state)
>   return -ENOMEM;
>
>   plane_state->crtc = crtc;
> - plane_state->fb = fb;
> + drm_atomic_set_fb_for_plane(plane_state, fb);
>   plane_state->crtc_x = crtc_x;
>   plane_state->crtc_y = crtc_y;
>   plane_state->crtc_h = crtc_h;
> @@ -550,15 +551,14 @@ int drm_plane_helper_disable(struct drm_plane *plane)
>   if (plane->funcs->atomic_duplicate_state)
>   plane_state = plane->funcs->atomic_duplicate_state(plane);
>   else if (plane->state)
> - plane_state = kmemdup(plane->state, sizeof(*plane_state),
> -      GFP_KERNEL);
> + plane_state = drm_atomic_helper_plane_duplicate_state(plane);
>   else
>   plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
>   if (!plane_state)
>   return -ENOMEM;
>
>   plane_state->crtc = NULL;
> - plane_state->fb = NULL;
> + drm_atomic_set_fb_for_plane(plane_state, NULL);
>
>   return drm_plane_helper_commit(plane, plane_state, plane->fb);
>  }
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 753812034e71..52d92981209f 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -45,6 +45,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
>
>  int drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
>    struct drm_crtc *crtc);
> +void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
> + struct drm_framebuffer *fb);
>  int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
>        struct drm_crtc *crtc);
>  int
> --
> 2.1.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 14/17] drm/atomic-helper: implement ->page_flip
  2014-11-06 17:43   ` [PATCH 14/17] " Sean Paul
@ 2014-11-06 18:13     ` Daniel Vetter
  2014-11-06 18:53       ` Sean Paul
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-06 18:13 UTC (permalink / raw)
  To: Sean Paul; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Thu, Nov 06, 2014 at 12:43:34PM -0500, Sean Paul wrote:
> On Sun, Nov 02, 2014 at 02:19:27PM +0100, Daniel Vetter wrote:
> > + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> > +retry:
> > + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> > + if (IS_ERR(crtc_state)) {
> > + ret = PTR_ERR(crtc_state);
> > + if (ret == -EDEADLK)
> > + goto backoff;
> > + else
> > + goto fail;
> 
> This function would benefit from the error cleanup you did in the previous
> patch (ie, doing the -EDEADLK check in fail and punting to backoff there).

v6 in in this subthread has that already. Can you please check that this
one's good?

Thanks, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces
  2014-11-05 21:44     ` Daniel Vetter
@ 2014-11-06 18:28       ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 18:28 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Wed, Nov 5, 2014 at 4:44 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> I've applied all the other nits, replies to the more interesting bits
> below.
>
> On Wed, Nov 05, 2014 at 01:53:48PM -0500, Sean Paul wrote:
>> On Sun, Nov 02, 2014 at 02:19:23PM +0100, Daniel Vetter wrote:
>> > + if (new_encoder != connector_state->best_encoder) {
>>
>> nit: If you just returned early when the encoder doesn't change, you can save
>> indentation and line breaks.
>
> Hm, that would mean either a goto (I don't like that for non-exceptional
> control flow) or duplicating the debug output. I'll go with the latter and
> frob it a bit.
>

I think you can just move the debug output above the new_encoder ==
connector_state->best_encoder check.

>> > + return ret;
>> > +
>> > + has_connectors = drm_atomic_connectors_for_crtc(state,
>> > + crtc);
>> > +
>> > + if (crtc_state->enable != has_connectors) {
>>
>> This makes me a little nervous. Even though has_connectors is a bool,
>> drm_atomic_connectors_for_crtc returns an int, and this seems like something
>> that someone might "fix" in the future.
>>
>> [PATCH] drm/atomic: Use proper type for drm_atomic_connectors_for_crtc
>
> Hm, yeah. I'll rename to num_connectors and add a !!. The idea of
> returning an int and not just a bool is that drivers might care if there's
> more than one, i.e. for cloned setups. At least i915 has some special
> considerations for that in some cases.
>

Makes sense, it just jumped out at me as something that might not be
future-safe.

>
>> > + ret = drm_crtc_vblank_get(crtc);
>> > + if (ret != 0)
>> > + continue;
>> > +
>> > + old_crtc_state->enable = true;
>> > + old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);
>>
>> I think you should collect last_vblank_count before drm_crtc_vblank_get
>
> vblank_get should block on anything, and I'm not sure whether the
> drm_vblank_count can't just fall over if vblank_get fails (since
> vblank_get before vblank_count is the pattern drm_irq.c uses iirc). So I'd
> prefer it this way round just for paranoia. So I think I'll stick with
> this scheme. The waiting is only done once we've grabbed all the vblank
> count, and that's the important part to ensure we don't wait for too long.
>
> This really is just all part of the "generic code has no idea about the
> dpms state of a crtc". I'll plan to fix that with the missing dpms on
> atomic pieces.

Ok, sounds reasonable. The fixup in your tree looks good, feel free to
add my R-b when you squash.

Sean


> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm/atomic-helper: implementatations for legacy interfaces
  2014-11-05 22:01         ` Daniel Vetter
@ 2014-11-06 18:31           ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 18:31 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Wed, Nov 5, 2014 at 5:01 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Nov 05, 2014 at 02:48:48PM -0500, Sean Paul wrote:
>> > + if (!crtc && crtc != set->crtc)
>>
>> I think this should be an ||
>
> Hm. My idea idea was actually something along the lines of
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 4f80885de3f6..077c792c46e0 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1271,7 +1271,14 @@ static int update_output_state(struct drm_atomic_state *state,
>                 struct drm_crtc *crtc = state->crtcs[i];
>                 struct drm_crtc_state *crtc_state = state->crtc_states[i];
>
> -               if (!crtc && crtc != set->crtc)
> +               if (!crtc)
> +                       continue;
> +
> +               /* 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;
>
>                 crtc_state->enable =
>
>
> I.e. that we don't recompute the new enable state for set->crtc so that we
> can catch bug in the helper function or core drm code which maps the
> legacy ->set_config to the atomic interface.
>
> Still r-b with that change applied, or want to take a deeper look again?

Fixup looks good to me, please add my R-b.

Sean

> -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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 14/17] drm/atomic-helper: implement ->page_flip
  2014-11-06 18:13     ` Daniel Vetter
@ 2014-11-06 18:53       ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 18:53 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Thu, Nov 6, 2014 at 1:13 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Thu, Nov 06, 2014 at 12:43:34PM -0500, Sean Paul wrote:
> > On Sun, Nov 02, 2014 at 02:19:27PM +0100, Daniel Vetter wrote:
> > > + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
> > > +retry:
> > > + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> > > + if (IS_ERR(crtc_state)) {
> > > + ret = PTR_ERR(crtc_state);
> > > + if (ret == -EDEADLK)
> > > + goto backoff;
> > > + else
> > > + goto fail;
> >
> > This function would benefit from the error cleanup you did in the previous
> > patch (ie, doing the -EDEADLK check in fail and punting to backoff there).
>
> v6 in in this subthread has that already. Can you please check that this
> one's good?
>

Yep, looks good.

Sean

>
> Thanks, Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
  2014-11-03 14:45   ` Daniel Thompson
  2014-11-06 17:43   ` Sean Paul
@ 2014-11-06 19:55   ` Daniel Vetter
  2 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2014-11-06 19:55 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

The atomic users and helpers assume that there is always a obj->state
structure around. Which means drivers need to somehow create that at
driver load time. Also it should obviously reset hardware state, so
needs to be reset upon resume.

Finally the destroy/duplicate_state functions are an awful lot of
boilerplate if the driver doesn't need anything beyond the default
state objects.

So add helper functions for all of this.

v2: Somehow the plane/connector versions got lost in the first
version.

v3: Add kerneldoc.

v4: Make duplicate_state functions a bit more robust, which is useful
for debugging state tracking issues when transitioning to atomic.

v5: Clear temporary variables in the crtc state when duplicating it,
like ->mode_changed or ->planes_changed. If we don't do this stale
values for these might pollute the next atomic modeset.

v6: Also clear crtc_state->event in case the driver didn't (yet) clear
this out.

v7: Split out wrong squashed commit. Also improve the kerneldoc to
mention that obj->state can be NULL and when.  Both suggested by
Daniel Thompson.

Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic_helper.c | 149 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  19 +++++
 2 files changed, 168 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index a3216a7f7ccc..2c38bda217ec 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1706,3 +1706,152 @@ backoff:
 	goto retry;
 }
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+
+/**
+ * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
+ * @crtc: drm CRTC
+ *
+ * Resets the atomic state for @crtc by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
+{
+	kfree(crtc->state);
+	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
+
+/**
+ * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
+ * @crtc: drm CRTC
+ *
+ * Default CRTC state duplicate hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *state;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
+
+	if (state) {
+		state->mode_changed = false;
+		state->planes_changed = false;
+		state->event = NULL;
+	}
+
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
+
+/**
+ * drm_atomic_helper_crtc_destroy_state - default state destroy hook
+ * @crtc: drm CRTC
+ * @state: CRTC state object to release
+ *
+ * Default CRTC state destroy hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * drm_atomic_helper_plane_reset - default ->reset hook for planes
+ * @plane: drm plane
+ *
+ * Resets the atomic state for @plane by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_plane_reset(struct drm_plane *plane)
+{
+	kfree(plane->state);
+	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
+
+/**
+ * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
+ * @plane: drm plane
+ *
+ * Default plane state duplicate hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
+{
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	return kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
+
+/**
+ * drm_atomic_helper_plane_destroy_state - default state destroy hook
+ * @plane: drm plane
+ * @state: plane state object to release
+ *
+ * Default plane state destroy hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
+
+/**
+ * drm_atomic_helper_connector_reset - default ->reset hook for connectors
+ * @connector: drm connector
+ *
+ * Resets the atomic state for @connector by freeing the state pointer (which
+ * might be NULL, e.g. at driver load time) and allocating a new empty state
+ * object.
+ */
+void drm_atomic_helper_connector_reset(struct drm_connector *connector)
+{
+	kfree(connector->state);
+	connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+
+/**
+ * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
+ * @connector: drm connector
+ *
+ * Default connector state duplicate hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+struct drm_connector_state *
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
+{
+	if (WARN_ON(!connector->state))
+		return NULL;
+
+	return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
+
+/**
+ * drm_atomic_helper_connector_destroy_state - default state destroy hook
+ * @connector: drm connector
+ * @state: connector state object to release
+ *
+ * Default connector state destroy hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+					  struct drm_connector_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 28a2f3a815fd..67e3c4645ae0 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -74,5 +74,24 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
 				struct drm_pending_vblank_event *event,
 				uint32_t flags);
 
+/* default implementations for state handling */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state);
+
+void drm_atomic_helper_plane_reset(struct drm_plane *plane);
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state);
+
+void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+struct drm_connector_state *
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+					  struct drm_connector_state *state);
+
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
-- 
2.1.1

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

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-06 17:43   ` Sean Paul
@ 2014-11-06 19:57     ` Daniel Vetter
  2014-11-06 20:01       ` Sean Paul
  0 siblings, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-06 19:57 UTC (permalink / raw)
  To: Sean Paul; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Thu, Nov 06, 2014 at 12:43:43PM -0500, Sean Paul wrote:
> On Sun, Nov 02, 2014 at 02:19:28PM +0100, Daniel Vetter wrote:
> > The atomic users and helpers assume that there is always a obj->state
> > structure around. Which means drivers need to somehow create that at
> > driver load time. Also it should obviously reset hardware state, so
> > needs to be reset upon resume.
> >
> > Finally the destroy/duplicate_state functions are an awful lot of
> > boilerplate if the driver doesn't need anything beyond the default
> > state objects.
> >
> > So add helper functions for all of this.
> >
> > v2: Somehow the plane/connector versions got lost in the first
> > version.
> >
> > v3: Add kerneldoc.
> >
> > v4: Make duplicate_state functions a bit more robust, which is useful
> > for debugging state tracking issues when transitioning to atomic.
> >
> > v5: Clear temporary variables in the crtc state when duplicating it,
> > like ->mode_changed or ->planes_changed. If we don't do this stale
> > values for these might pollute the next atomic modeset.
> >
> > v6: Also clear crtc_state->event in case the driver didn't (yet) clear
> > this out.
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Minus the fixup nits that danielt pointed out

Yeah already fixed them but forgotten to resend the patch. Done now.
> 
> Reviewed-by: Sean Paul <seanpaul@chromium.org>

Can you please double check that the new version is ok?

Thanks, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH] drm: Docbook integration and over sections for all the new helpers
  2014-11-02 13:19 ` [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers Daniel Vetter
  2014-11-06 17:43   ` Sean Paul
@ 2014-11-06 20:00   ` Daniel Vetter
  2014-11-06 20:02     ` Sean Paul
  1 sibling, 1 reply; 77+ messages in thread
From: Daniel Vetter @ 2014-11-06 20:00 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter, Intel Graphics Development

In all cases the text requires that new drivers are converted to the
atomic interfaces.

v2: Add overview for state handling.

v3: Review from Sean: Some spelling fixes and drop the misguided
hunk to remove rgba8888 from the plane helpers compat list.

Cc: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl      | 20 +++++++++++++++++++-
 drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_helper.c   | 20 ++++++++++++++++++++
 drivers/gpu/drm/drm_plane_helper.c  | 26 ++++++++++++++++++++++++++
 4 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 748513b34025..f276c2cf806b 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2324,8 +2324,25 @@ void intel_crt_init(struct drm_device *dev)
       </itemizedlist>
     </sect2>
     <sect2>
+      <title>Atomic Modeset Helper Functions Reference</title>
+      <sect3>
+	<title>Overview</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c overview
+      </sect3>
+      <sect3>
+	<title>Implementing Asynchronous Atomic Commit</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c implementing async commit
+      </sect3>
+      <sect3>
+	<title>Atomic State Reset and Initialization</title>
+!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
+      </sect3>
+!Edrivers/gpu/drm/drm_atomic_helper.c
+    </sect2>
+    <sect2>
       <title>Modeset Helper Functions Reference</title>
 !Edrivers/gpu/drm/drm_crtc_helper.c
+!Pdrivers/gpu/drm/drm_crtc_helper.c overview
     </sect2>
     <sect2>
       <title>Output Probing Helper Functions Reference</title>
@@ -2379,7 +2396,8 @@ void intel_crt_init(struct drm_device *dev)
     </sect2>
     <sect2>
       <title id="drm-kms-planehelpers">Plane Helper Reference</title>
-!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
+!Edrivers/gpu/drm/drm_plane_helper.c
+!Pdrivers/gpu/drm/drm_plane_helper.c overview
     </sect2>
   </sect1>
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2c38bda217ec..2b1db0c12fdc 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -32,6 +32,27 @@
 #include <drm/drm_atomic_helper.h>
 #include <linux/fence.h>
 
+/**
+ * DOC: overview
+ *
+ * This helper library provides implementations of check and commit functions on
+ * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
+ * also provides convenience implementations for the atomic state handling
+ * callbacks for drivers which don't need to subclass the drm core structures to
+ * add their own additional internal state.
+ *
+ * This library also provides default implementations for the check callback in
+ * drm_atomic_helper_check and for the commit callback with
+ * drm_atomic_helper_commit. But the individual stages and callbacks are expose
+ * to allow drivers to mix and match and e.g. use the plane helpers only
+ * together with a driver private modeset implementation.
+ *
+ * This library also provides implementations for all the legacy driver
+ * interfaces on top of the atomic interface. See drm_atomic_helper_set_config,
+ * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the
+ * various functions to implement set_property callbacks. New drivers must not
+ * implement these functions themselves but must use the provided helpers.
+ */
 static void
 drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
 				struct drm_plane_state *plane_state,
@@ -1708,6 +1729,21 @@ backoff:
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
 
 /**
+ * DOC: atomic state reset and initialization
+ *
+ * Both the drm core and the atomic helpers assume that there is always the full
+ * and correct atomic software state for all connectors, CRTCs and planes
+ * available. Which is a bit a problem on driver load and also after system
+ * suspend. One way to solve this is to have a hardware state read-out
+ * infrastructure which reconstructs the full software state (e.g. the i915
+ * driver).
+ *
+ * The simpler solution is to just reset the software state to everything off,
+ * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
+ * the atomic helpers provide default reset implementations for all hooks.
+ */
+
+/**
  * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
  * @crtc: drm CRTC
  *
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 46728a8ac622..33195e9adaab 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -41,6 +41,26 @@
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_edid.h>
 
+/**
+ * DOC: overview
+ *
+ * The CRTC modeset helper library provides a default set_config implementation
+ * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
+ * the same callbacks which drivers can use to e.g. restore the modeset
+ * configuration on resume with drm_helper_resume_force_mode().
+ *
+ * The driver callbacks are mostly compatible with the atomic modeset helpers,
+ * except for the handling of the primary plane: Atomic helpers require that the
+ * primary plane is implemented as a real standalone plane and not directly tied
+ * to the CRTC state. For easier transition this library provides functions to
+ * implement the old semantics required by the CRTC helpers using the new plane
+ * and atomic helper callbacks.
+ *
+ * Drivers are strongly urged to convert to the atomic helpers (by way of first
+ * converting to the plane helpers). New drivers must not use these functions
+ * but need to implement the atomic interface instead, potentially using the
+ * atomic helpers for that.
+ */
 MODULE_AUTHOR("David Airlie, Jesse Barnes");
 MODULE_DESCRIPTION("DRM KMS helper");
 MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index a5a295872fbb..fa56bb5da6c3 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -31,6 +31,32 @@
 
 #define SUBPIXEL_MASK 0xffff
 
+/**
+ * DOC: overview
+ *
+ * This helper library has two parts. The first part has support to implement
+ * primary plane support on top of the normal CRTC configuration interface.
+ * Since the legacy ->set_config interface ties the primary plane together with
+ * the CRTC state this does not allow userspace to disable the primary plane
+ * itself.  To avoid too much duplicated code use
+ * drm_plane_helper_check_update() which can be used to enforce the same
+ * restrictions as primary planes had thus. The default primary plane only
+ * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
+ * framebuffer.
+ *
+ * Drivers are highly recommended to implement proper support for primary
+ * planes, and newly merged drivers must not rely upon these transitional
+ * helpers.
+ *
+ * The second part also implements transitional helpers which allow drivers to
+ * gradually switch to the atomic helper infrastructure for plane updates. Once
+ * that switch is complete drivers shouldn't use these any longer, instead using
+ * the proper legacy implementations for update and disable plane hooks provided
+ * by the atomic helpers.
+ *
+ * Again drivers are strongly urged to switch to the new interfaces.
+ */
+
 /*
  * This is the minimal list of formats that seem to be safe for modeset use
  * with all current DRM drivers.  Most hardware can actually support more
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset
  2014-11-06 19:57     ` Daniel Vetter
@ 2014-11-06 20:01       ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 20:01 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, DRI Development

On Thu, Nov 6, 2014 at 2:57 PM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Thu, Nov 06, 2014 at 12:43:43PM -0500, Sean Paul wrote:
>> On Sun, Nov 02, 2014 at 02:19:28PM +0100, Daniel Vetter wrote:
>> > The atomic users and helpers assume that there is always a obj->state
>> > structure around. Which means drivers need to somehow create that at
>> > driver load time. Also it should obviously reset hardware state, so
>> > needs to be reset upon resume.
>> >
>> > Finally the destroy/duplicate_state functions are an awful lot of
>> > boilerplate if the driver doesn't need anything beyond the default
>> > state objects.
>> >
>> > So add helper functions for all of this.
>> >
>> > v2: Somehow the plane/connector versions got lost in the first
>> > version.
>> >
>> > v3: Add kerneldoc.
>> >
>> > v4: Make duplicate_state functions a bit more robust, which is useful
>> > for debugging state tracking issues when transitioning to atomic.
>> >
>> > v5: Clear temporary variables in the crtc state when duplicating it,
>> > like ->mode_changed or ->planes_changed. If we don't do this stale
>> > values for these might pollute the next atomic modeset.
>> >
>> > v6: Also clear crtc_state->event in case the driver didn't (yet) clear
>> > this out.
>> >
>> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>> Minus the fixup nits that danielt pointed out
>
> Yeah already fixed them but forgotten to resend the patch. Done now.
>>
>> Reviewed-by: Sean Paul <seanpaul@chromium.org>
>
> Can you please double check that the new version is ok?
>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> Thanks, Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH] drm: Docbook integration and over sections for all the new helpers
  2014-11-06 20:00   ` [PATCH] " Daniel Vetter
@ 2014-11-06 20:02     ` Sean Paul
  0 siblings, 0 replies; 77+ messages in thread
From: Sean Paul @ 2014-11-06 20:02 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, DRI Development

On Thu, Nov 6, 2014 at 3:00 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> In all cases the text requires that new drivers are converted to the
> atomic interfaces.
>
> v2: Add overview for state handling.
>
> v3: Review from Sean: Some spelling fixes and drop the misguided
> hunk to remove rgba8888 from the plane helpers compat list.
>
> Cc: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  Documentation/DocBook/drm.tmpl      | 20 +++++++++++++++++++-
>  drivers/gpu/drm/drm_atomic_helper.c | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_helper.c   | 20 ++++++++++++++++++++
>  drivers/gpu/drm/drm_plane_helper.c  | 26 ++++++++++++++++++++++++++
>  4 files changed, 101 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 748513b34025..f276c2cf806b 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -2324,8 +2324,25 @@ void intel_crt_init(struct drm_device *dev)
>        </itemizedlist>
>      </sect2>
>      <sect2>
> +      <title>Atomic Modeset Helper Functions Reference</title>
> +      <sect3>
> +       <title>Overview</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c overview
> +      </sect3>
> +      <sect3>
> +       <title>Implementing Asynchronous Atomic Commit</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c implementing async commit
> +      </sect3>
> +      <sect3>
> +       <title>Atomic State Reset and Initialization</title>
> +!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
> +      </sect3>
> +!Edrivers/gpu/drm/drm_atomic_helper.c
> +    </sect2>
> +    <sect2>
>        <title>Modeset Helper Functions Reference</title>
>  !Edrivers/gpu/drm/drm_crtc_helper.c
> +!Pdrivers/gpu/drm/drm_crtc_helper.c overview
>      </sect2>
>      <sect2>
>        <title>Output Probing Helper Functions Reference</title>
> @@ -2379,7 +2396,8 @@ void intel_crt_init(struct drm_device *dev)
>      </sect2>
>      <sect2>
>        <title id="drm-kms-planehelpers">Plane Helper Reference</title>
> -!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
> +!Edrivers/gpu/drm/drm_plane_helper.c
> +!Pdrivers/gpu/drm/drm_plane_helper.c overview
>      </sect2>
>    </sect1>
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 2c38bda217ec..2b1db0c12fdc 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -32,6 +32,27 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <linux/fence.h>
>
> +/**
> + * DOC: overview
> + *
> + * This helper library provides implementations of check and commit functions on
> + * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
> + * also provides convenience implementations for the atomic state handling
> + * callbacks for drivers which don't need to subclass the drm core structures to
> + * add their own additional internal state.
> + *
> + * This library also provides default implementations for the check callback in
> + * drm_atomic_helper_check and for the commit callback with
> + * drm_atomic_helper_commit. But the individual stages and callbacks are expose
> + * to allow drivers to mix and match and e.g. use the plane helpers only
> + * together with a driver private modeset implementation.
> + *
> + * This library also provides implementations for all the legacy driver
> + * interfaces on top of the atomic interface. See drm_atomic_helper_set_config,
> + * drm_atomic_helper_disable_plane, drm_atomic_helper_disable_plane and the
> + * various functions to implement set_property callbacks. New drivers must not
> + * implement these functions themselves but must use the provided helpers.
> + */
>  static void
>  drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
>                                 struct drm_plane_state *plane_state,
> @@ -1708,6 +1729,21 @@ backoff:
>  EXPORT_SYMBOL(drm_atomic_helper_page_flip);
>
>  /**
> + * DOC: atomic state reset and initialization
> + *
> + * Both the drm core and the atomic helpers assume that there is always the full
> + * and correct atomic software state for all connectors, CRTCs and planes
> + * available. Which is a bit a problem on driver load and also after system
> + * suspend. One way to solve this is to have a hardware state read-out
> + * infrastructure which reconstructs the full software state (e.g. the i915
> + * driver).
> + *
> + * The simpler solution is to just reset the software state to everything off,
> + * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
> + * the atomic helpers provide default reset implementations for all hooks.
> + */
> +
> +/**
>   * drm_atomic_helper_crtc_reset - default ->reset hook for CRTCs
>   * @crtc: drm CRTC
>   *
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 46728a8ac622..33195e9adaab 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -41,6 +41,26 @@
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_edid.h>
>
> +/**
> + * DOC: overview
> + *
> + * The CRTC modeset helper library provides a default set_config implementation
> + * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
> + * the same callbacks which drivers can use to e.g. restore the modeset
> + * configuration on resume with drm_helper_resume_force_mode().
> + *
> + * The driver callbacks are mostly compatible with the atomic modeset helpers,
> + * except for the handling of the primary plane: Atomic helpers require that the
> + * primary plane is implemented as a real standalone plane and not directly tied
> + * to the CRTC state. For easier transition this library provides functions to
> + * implement the old semantics required by the CRTC helpers using the new plane
> + * and atomic helper callbacks.
> + *
> + * Drivers are strongly urged to convert to the atomic helpers (by way of first
> + * converting to the plane helpers). New drivers must not use these functions
> + * but need to implement the atomic interface instead, potentially using the
> + * atomic helpers for that.
> + */
>  MODULE_AUTHOR("David Airlie, Jesse Barnes");
>  MODULE_DESCRIPTION("DRM KMS helper");
>  MODULE_LICENSE("GPL and additional rights");
> diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
> index a5a295872fbb..fa56bb5da6c3 100644
> --- a/drivers/gpu/drm/drm_plane_helper.c
> +++ b/drivers/gpu/drm/drm_plane_helper.c
> @@ -31,6 +31,32 @@
>
>  #define SUBPIXEL_MASK 0xffff
>
> +/**
> + * DOC: overview
> + *
> + * This helper library has two parts. The first part has support to implement
> + * primary plane support on top of the normal CRTC configuration interface.
> + * Since the legacy ->set_config interface ties the primary plane together with
> + * the CRTC state this does not allow userspace to disable the primary plane
> + * itself.  To avoid too much duplicated code use
> + * drm_plane_helper_check_update() which can be used to enforce the same
> + * restrictions as primary planes had thus. The default primary plane only
> + * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
> + * framebuffer.
> + *
> + * Drivers are highly recommended to implement proper support for primary
> + * planes, and newly merged drivers must not rely upon these transitional
> + * helpers.
> + *
> + * The second part also implements transitional helpers which allow drivers to
> + * gradually switch to the atomic helper infrastructure for plane updates. Once
> + * that switch is complete drivers shouldn't use these any longer, instead using
> + * the proper legacy implementations for update and disable plane hooks provided
> + * by the atomic helpers.
> + *
> + * Again drivers are strongly urged to switch to the new interfaces.
> + */
> +
>  /*
>   * This is the minimal list of formats that seem to be safe for modeset use
>   * with all current DRM drivers.  Most hardware can actually support more
> --
> 2.1.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [Intel-gfx] [PATCH] drm: Global atomic state handling
  2014-11-05 17:06           ` Daniel Vetter
@ 2015-02-06  9:58             ` Jani Nikula
  2015-02-06 21:14               ` Daniel Vetter
  0 siblings, 1 reply; 77+ messages in thread
From: Jani Nikula @ 2015-02-06  9:58 UTC (permalink / raw)
  To: DRI Development
  Cc: Daniel Vetter, Daniel Thompson, Fengguang Wu, Intel Graphics Development

On Wed, 05 Nov 2014, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:

[heavily edited to just show the debugs]

> +struct drm_atomic_state *
> +drm_atomic_state_alloc(struct drm_device *dev)
> +{
> +	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
> +}

> +void drm_atomic_state_clear(struct drm_atomic_state *state)
> +{
> +	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
> +}

> +void drm_atomic_state_free(struct drm_atomic_state *state)
> +{
> +	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
> +}

> +struct drm_crtc_state *
> +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> +			  struct drm_crtc *crtc)
> +{
> +	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
> +		      crtc->base.id, crtc_state, state);
> +}

> +struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> +			  struct drm_plane *plane)
> +{
> +	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> +		      plane->base.id, plane_state, state);
> +}

> +struct drm_connector_state *
> +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> +			  struct drm_connector *connector)
> +{
> +	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
> +		      connector->base.id, connector_state, state);
> +}

> +int drm_atomic_check_only(struct drm_atomic_state *state)
> +{
> +	DRM_DEBUG_KMS("checking %p\n", state);
> +}

> +int drm_atomic_commit(struct drm_atomic_state *state)
> +{
> +	DRM_DEBUG_KMS("commiting %p\n", state);
> +}

These seem to be rather verbose [1], is this normal or indicative of
something going awry? If normal, it does seem quite noisy in the logs.

BR,
Jani.


[1] https://bugs.freedesktop.org/attachment.cgi?id=113217

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [Intel-gfx] [PATCH] drm: Global atomic state handling
  2015-02-06  9:58             ` [Intel-gfx] " Jani Nikula
@ 2015-02-06 21:14               ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2015-02-06 21:14 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Daniel Thompson, Daniel Vetter, Intel Graphics Development,
	DRI Development, Fengguang Wu

On Fri, Feb 06, 2015 at 11:58:58AM +0200, Jani Nikula wrote:
> On Wed, 05 Nov 2014, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> 
> [heavily edited to just show the debugs]
> 
> > +struct drm_atomic_state *
> > +drm_atomic_state_alloc(struct drm_device *dev)
> > +{
> > +	DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
> > +}
> 
> > +void drm_atomic_state_clear(struct drm_atomic_state *state)
> > +{
> > +	DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
> > +}
> 
> > +void drm_atomic_state_free(struct drm_atomic_state *state)
> > +{
> > +	DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
> > +}
> 
> > +struct drm_crtc_state *
> > +drm_atomic_get_crtc_state(struct drm_atomic_state *state,
> > +			  struct drm_crtc *crtc)
> > +{
> > +	DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
> > +		      crtc->base.id, crtc_state, state);
> > +}
> 
> > +struct drm_plane_state *
> > +drm_atomic_get_plane_state(struct drm_atomic_state *state,
> > +			  struct drm_plane *plane)
> > +{
> > +	DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
> > +		      plane->base.id, plane_state, state);
> > +}
> 
> > +struct drm_connector_state *
> > +drm_atomic_get_connector_state(struct drm_atomic_state *state,
> > +			  struct drm_connector *connector)
> > +{
> > +	DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
> > +		      connector->base.id, connector_state, state);
> > +}
> 
> > +int drm_atomic_check_only(struct drm_atomic_state *state)
> > +{
> > +	DRM_DEBUG_KMS("checking %p\n", state);
> > +}
> 
> > +int drm_atomic_commit(struct drm_atomic_state *state)
> > +{
> > +	DRM_DEBUG_KMS("commiting %p\n", state);
> > +}
> 
> These seem to be rather verbose [1], is this normal or indicative of
> something going awry? If normal, it does seem quite noisy in the logs.

For debugging screw-ups in the state-preparetion, checks and commit
they're fairly useful imo. So definitely valuable for developing atomic
drivers.

Should we instead have a new DRM_DEBUG_ATOMIC to be able to filter these
out as needed?
-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
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2015-02-06 21:13 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-02 13:19 [PATCH 00/17] atomic modeset core<->driver interfaces and helpers Daniel Vetter
2014-11-02 13:19 ` [PATCH 01/17] drm: Move drm_crtc_init from drm_crtc.h to drm_plane_helper.h Daniel Vetter
2014-11-04 20:31   ` Sean Paul
2014-11-02 13:19 ` [PATCH 02/17] drm: Pull drm_crtc.h into the kerneldoc template Daniel Vetter
2014-11-02 19:18   ` [PATCH] " Daniel Vetter
2014-11-03  3:04     ` Thierry Reding
2014-11-02 13:19 ` [PATCH 03/17] drm: fixup kerneldoc in drm_crtc.h Daniel Vetter
2014-11-02 19:19   ` Daniel Vetter
2014-11-02 13:19 ` [PATCH 04/17] drm/modeset_lock: document trylock_only in kerneldoc Daniel Vetter
2014-11-04 20:31   ` Sean Paul
2014-11-05 16:18   ` Thierry Reding
2014-11-02 13:19 ` [PATCH 05/17] drm: Add atomic driver interface definitions for objects Daniel Vetter
2014-11-04 20:31   ` Sean Paul
2014-11-05 16:26   ` Thierry Reding
2014-11-05 17:04     ` Daniel Vetter
2014-11-05 17:16       ` [Intel-gfx] " Damien Lespiau
2014-11-02 13:19 ` [PATCH 06/17] drm: Global atomic state handling Daniel Vetter
2014-11-03 23:41   ` Matt Roper
2014-11-04  8:40     ` Daniel Vetter
2014-11-04 20:31   ` Sean Paul
2014-11-04 21:30     ` Daniel Vetter
2014-11-04 21:41       ` Daniel Vetter
2014-11-04 21:37   ` [PATCH] " Daniel Vetter
2014-11-04 22:07     ` Daniel Vetter
2014-11-04 22:32       ` Sean Paul
2014-11-05 13:06       ` Ander Conselvan de Oliveira
2014-11-05 13:45       ` Daniel Vetter
2014-11-05 14:22         ` Daniel Vetter
2014-11-05 17:06           ` Daniel Vetter
2015-02-06  9:58             ` [Intel-gfx] " Jani Nikula
2015-02-06 21:14               ` Daniel Vetter
2014-11-02 13:19 ` [PATCH 07/17] drm: Add atomic/plane helpers Daniel Vetter
2014-11-04 22:30   ` Sean Paul
2014-11-04 23:16     ` Daniel Vetter
2014-11-02 13:19 ` [PATCH 08/17] drm/plane-helper: transitional atomic plane helpers Daniel Vetter
2014-11-05 16:45   ` Sean Paul
2014-11-05 16:51     ` Daniel Vetter
2014-11-05 16:59   ` [PATCH] " Daniel Vetter
2014-11-02 13:19 ` [PATCH 09/17] drm/crtc-helper: Transitional functions using " Daniel Vetter
2014-11-05 17:42   ` Sean Paul
2014-11-02 13:19 ` [PATCH 10/17] drm: Atomic crtc/connector updates using crtc/plane helper interfaces Daniel Vetter
2014-11-05 18:53   ` Sean Paul
2014-11-05 21:44     ` Daniel Vetter
2014-11-06 18:28       ` Sean Paul
2014-11-02 13:19 ` [PATCH 11/17] drm/atomic-helper: implementatations for legacy interfaces Daniel Vetter
2014-11-04 22:08   ` [PATCH] " Daniel Vetter
2014-11-05 13:46     ` Daniel Vetter
2014-11-05 19:48       ` Sean Paul
2014-11-05 22:01         ` Daniel Vetter
2014-11-06 18:31           ` Sean Paul
2014-11-02 13:19 ` [PATCH 12/17] drm/atomic: Integrate fence support Daniel Vetter
2014-11-06 17:43   ` [Intel-gfx] " Sean Paul
2014-11-02 13:19 ` [PATCH 13/17] drm/atomic-helpers: document how to implement async commit Daniel Vetter
2014-11-06 17:43   ` Sean Paul
2014-11-02 13:19 ` [PATCH 14/17] drm/atomic-helper: implement ->page_flip Daniel Vetter
2014-11-04 22:09   ` [PATCH] " Daniel Vetter
2014-11-05 11:35     ` Daniel Thompson
2014-11-05 13:46     ` Daniel Vetter
2014-11-06 17:43   ` [PATCH 14/17] " Sean Paul
2014-11-06 18:13     ` Daniel Vetter
2014-11-06 18:53       ` Sean Paul
2014-11-02 13:19 ` [PATCH 15/17] drm/atomic-helpers: functions for state duplicate/destroy/reset Daniel Vetter
2014-11-03 14:45   ` Daniel Thompson
2014-11-03 14:53     ` Daniel Vetter
2014-11-03 15:06       ` Daniel Thompson
2014-11-03 15:11         ` Daniel Vetter
2014-11-06 17:43   ` Sean Paul
2014-11-06 19:57     ` Daniel Vetter
2014-11-06 20:01       ` Sean Paul
2014-11-06 19:55   ` [PATCH] " Daniel Vetter
2014-11-02 13:19 ` [PATCH 16/17] drm: Docbook integration and over sections for all the new helpers Daniel Vetter
2014-11-06 17:43   ` Sean Paul
2014-11-06 20:00   ` [PATCH] " Daniel Vetter
2014-11-06 20:02     ` Sean Paul
2014-11-02 13:19 ` [PATCH 17/17] drm/atomic: Refcounting for plane_state->fb Daniel Vetter
2014-11-04 21:57   ` [PATCH] " Daniel Vetter
2014-11-06 17:44   ` [PATCH 17/17] " Sean Paul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.