diff mbox

[2/4,v3] drm: Introduce drm_connector_register_all() helper

Message ID 1458722577-20283-3-git-send-email-abrodkin@synopsys.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alexey Brodkin March 23, 2016, 8:42 a.m. UTC
As a pair to already existing drm_connector_unregister_all() we're adding
generic implementation of what is already done in some drivers.

Once this helper is implemented we'll be ready to switch existing
driver-specific implementations with the generic one.

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: David Airlie <airlied@linux.ie>
---

Changes v2 -> v3:
 * Updated title with capital after colon
 * Simplified failure path with direct and unconditional invocation of
   unregister_all()
 * Updated kerneldoc description of the drm_connector_register_all()

Changes v1 -> v2:
 * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
 * Use drm_for_each_connector() instead of list_for_each_entry()
 * Updated kerneldoc for drm_dev_register()

 drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c  |  6 +++++-
 include/drm/drm_crtc.h     |  3 ++-
 3 files changed, 50 insertions(+), 2 deletions(-)

Comments

David Herrmann March 23, 2016, 11:13 a.m. UTC | #1
Hi

On Wed, Mar 23, 2016 at 9:42 AM, Alexey Brodkin
<Alexey.Brodkin@synopsys.com> wrote:
> As a pair to already existing drm_connector_unregister_all() we're adding
> generic implementation of what is already done in some drivers.
>
> Once this helper is implemented we'll be ready to switch existing
> driver-specific implementations with the generic one.
>
> Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: David Airlie <airlied@linux.ie>
> ---
>
> Changes v2 -> v3:
>  * Updated title with capital after colon
>  * Simplified failure path with direct and unconditional invocation of
>    unregister_all()
>  * Updated kerneldoc description of the drm_connector_register_all()
>
> Changes v1 -> v2:
>  * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
>  * Use drm_for_each_connector() instead of list_for_each_entry()
>  * Updated kerneldoc for drm_dev_register()
>
>  drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_drv.c  |  6 +++++-
>  include/drm/drm_crtc.h     |  3 ++-
>  3 files changed, 50 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 65488a6..21eea11 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1081,6 +1081,49 @@ void drm_connector_unregister(struct drm_connector *connector)
>  EXPORT_SYMBOL(drm_connector_unregister);
>
>  /**
> + * drm_connector_register_all - register all connectors
> + * @dev: drm device
> + *
> + * This function registers all connectors in sysfs and other places so that
> + * userspace can start to access them. Drivers can call it after calling
> + * drm_dev_register() to complete the device registration, if they don't call
> + * drm_connector_register() on each connector individually.
> + *
> + * When a device is unplugged and should be removed from userspace access,
> + * call drm_connector_unregister_all(), which is the inverse of this
> + * function.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + */
> +int drm_connector_register_all(struct drm_device *dev)
> +{
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +
> +       drm_for_each_connector(connector, dev) {
> +               ret = drm_connector_register(connector);
> +               if (ret) {
> +                       /*
> +                        * We may safely call unregister_all() here within
> +                        * area locked with mutex because unregister_all()
> +                        * doesn't use locks inside (see a comment in that
> +                        * function).
> +                        */

Ugh? unregister_all() says:

/* FIXME: taking the mode config mutex ends up in a clash with sysfs */

This strongly contradicts your comment. Anyway, regardless how you
want to fix it: You better unlock the mode-config mutex before
returning below.

Thanks
David

> +                       drm_connector_unregister_all(dev);
> +                       return ret;
> +               }
> +       }
> +
> +       mutex_unlock(&dev->mode_config.mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_connector_register_all);
> +
> +/**
>   * drm_connector_unregister_all - unregister connector userspace interfaces
>   * @dev: drm device
>   *
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 167c8d3..2c9a2b6 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -715,7 +715,11 @@ EXPORT_SYMBOL(drm_dev_unref);
>   *
>   * Register the DRM device @dev with the system, advertise device to user-space
>   * and start normal device operation. @dev must be allocated via drm_dev_alloc()
> - * previously.
> + * previously. Right after drm_dev_register() the driver should call
> + * drm_connector_register_all() to register all connectors in sysfs. This is
> + * a separate call for backward compatibility with drivers still using
> + * the deprecated ->load() callback, where connectors are registered from within
> + * the ->load() callback.
>   *
>   * Never call this twice on any device!
>   *
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 42d9f4d..6a34117 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -2214,7 +2214,8 @@ void drm_connector_unregister(struct drm_connector *connector);
>
>  extern void drm_connector_cleanup(struct drm_connector *connector);
>  extern unsigned int drm_connector_index(struct drm_connector *connector);
> -/* helper to unregister all connectors from sysfs for device */
> +/* helpers to {un}register all connectors from sysfs for device */
> +extern int drm_connector_register_all(struct drm_device *dev);
>  extern void drm_connector_unregister_all(struct drm_device *dev);
>
>  extern int drm_bridge_add(struct drm_bridge *bridge);
> --
> 2.5.0
>
Alexey Brodkin March 23, 2016, 1:41 p.m. UTC | #2
Hi David,

On Wed, 2016-03-23 at 12:13 +0100, David Herrmann wrote:
> Hi
> 
> On Wed, Mar 23, 2016 at 9:42 AM, Alexey Brodkin
> <Alexey.Brodkin@synopsys.com> wrote:
> > 
> > As a pair to already existing drm_connector_unregister_all() we're adding
> > generic implementation of what is already done in some drivers.
> > 
> > Once this helper is implemented we'll be ready to switch existing
> > driver-specific implementations with the generic one.
> > 
> > Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: David Airlie <airlied@linux.ie>
> > ---
> > 
> > Changes v2 -> v3:
> >  * Updated title with capital after colon
> >  * Simplified failure path with direct and unconditional invocation of
> >    unregister_all()
> >  * Updated kerneldoc description of the drm_connector_register_all()
> > 
> > Changes v1 -> v2:
> >  * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
> >  * Use drm_for_each_connector() instead of list_for_each_entry()
> >  * Updated kerneldoc for drm_dev_register()
> > 
> >  drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/drm_drv.c  |  6 +++++-
> >  include/drm/drm_crtc.h     |  3 ++-
> >  3 files changed, 50 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > index 65488a6..21eea11 100644
> > --- a/drivers/gpu/drm/drm_crtc.c
> > +++ b/drivers/gpu/drm/drm_crtc.c
> > @@ -1081,6 +1081,49 @@ void drm_connector_unregister(struct drm_connector *connector)
> >  EXPORT_SYMBOL(drm_connector_unregister);
> > 
> >  /**
> > + * drm_connector_register_all - register all connectors
> > + * @dev: drm device
> > + *
> > + * This function registers all connectors in sysfs and other places so that
> > + * userspace can start to access them. Drivers can call it after calling
> > + * drm_dev_register() to complete the device registration, if they don't call
> > + * drm_connector_register() on each connector individually.
> > + *
> > + * When a device is unplugged and should be removed from userspace access,
> > + * call drm_connector_unregister_all(), which is the inverse of this
> > + * function.
> > + *
> > + * Returns:
> > + * Zero on success, error code on failure.
> > + */
> > +int drm_connector_register_all(struct drm_device *dev)
> > +{
> > +       struct drm_connector *connector;
> > +       int ret;
> > +
> > +       mutex_lock(&dev->mode_config.mutex);
> > +
> > +       drm_for_each_connector(connector, dev) {
> > +               ret = drm_connector_register(connector);
> > +               if (ret) {
> > +                       /*
> > +                        * We may safely call unregister_all() here within
> > +                        * area locked with mutex because unregister_all()
> > +                        * doesn't use locks inside (see a comment in that
> > +                        * function).
> > +                        */
> Ugh? unregister_all() says:
> 
> /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
> 
> This strongly contradicts your comment. Anyway, regardless how you
> want to fix it: You better unlock the mode-config mutex before
> returning below.

So good catch.
But what I really meant since we didn't get any further after registering
all "good" connections (see we're not releasing mutex still) the will be
no clashes with sysfs.

Still I;d like Daniel to comment on that separately.

-Alexey
Daniel Vetter March 29, 2016, 8:19 a.m. UTC | #3
On Wed, Mar 23, 2016 at 01:41:05PM +0000, Alexey Brodkin wrote:
> Hi David,
> 
> On Wed, 2016-03-23 at 12:13 +0100, David Herrmann wrote:
> > Hi
> > 
> > On Wed, Mar 23, 2016 at 9:42 AM, Alexey Brodkin
> > <Alexey.Brodkin@synopsys.com> wrote:
> > > 
> > > As a pair to already existing drm_connector_unregister_all() we're adding
> > > generic implementation of what is already done in some drivers.
> > > 
> > > Once this helper is implemented we'll be ready to switch existing
> > > driver-specific implementations with the generic one.
> > > 
> > > Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Cc: David Airlie <airlied@linux.ie>
> > > ---
> > > 
> > > Changes v2 -> v3:
> > >  * Updated title with capital after colon
> > >  * Simplified failure path with direct and unconditional invocation of
> > >    unregister_all()
> > >  * Updated kerneldoc description of the drm_connector_register_all()
> > > 
> > > Changes v1 -> v2:
> > >  * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
> > >  * Use drm_for_each_connector() instead of list_for_each_entry()
> > >  * Updated kerneldoc for drm_dev_register()
> > > 
> > >  drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/gpu/drm/drm_drv.c  |  6 +++++-
> > >  include/drm/drm_crtc.h     |  3 ++-
> > >  3 files changed, 50 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > > index 65488a6..21eea11 100644
> > > --- a/drivers/gpu/drm/drm_crtc.c
> > > +++ b/drivers/gpu/drm/drm_crtc.c
> > > @@ -1081,6 +1081,49 @@ void drm_connector_unregister(struct drm_connector *connector)
> > >  EXPORT_SYMBOL(drm_connector_unregister);
> > > 
> > >  /**
> > > + * drm_connector_register_all - register all connectors
> > > + * @dev: drm device
> > > + *
> > > + * This function registers all connectors in sysfs and other places so that
> > > + * userspace can start to access them. Drivers can call it after calling
> > > + * drm_dev_register() to complete the device registration, if they don't call
> > > + * drm_connector_register() on each connector individually.
> > > + *
> > > + * When a device is unplugged and should be removed from userspace access,
> > > + * call drm_connector_unregister_all(), which is the inverse of this
> > > + * function.
> > > + *
> > > + * Returns:
> > > + * Zero on success, error code on failure.
> > > + */
> > > +int drm_connector_register_all(struct drm_device *dev)
> > > +{
> > > +       struct drm_connector *connector;
> > > +       int ret;
> > > +
> > > +       mutex_lock(&dev->mode_config.mutex);
> > > +
> > > +       drm_for_each_connector(connector, dev) {
> > > +               ret = drm_connector_register(connector);
> > > +               if (ret) {
> > > +                       /*
> > > +                        * We may safely call unregister_all() here within
> > > +                        * area locked with mutex because unregister_all()
> > > +                        * doesn't use locks inside (see a comment in that
> > > +                        * function).
> > > +                        */
> > Ugh? unregister_all() says:
> > 
> > /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
> > 
> > This strongly contradicts your comment. Anyway, regardless how you
> > want to fix it: You better unlock the mode-config mutex before
> > returning below.
> 
> So good catch.
> But what I really meant since we didn't get any further after registering
> all "good" connections (see we're not releasing mutex still) the will be
> no clashes with sysfs.
> 
> Still I;d like Daniel to comment on that separately.

I think doing the unregister_all outside of the loop&locked section is
better for future-proofing. My long-term plan for connector lifetimes and
the connector list is:
- refcounting for connectors (Dave has wip patches already).
- separate lock for the connector list (and only that).

Doing it entirely separate would make things easier and more robust.

I merged patch 1 meanwhile to drm-misc.

Thanks, Daniel
Alexey Brodkin March 29, 2016, 9:12 a.m. UTC | #4
Hi Daniel,

On Tue, 2016-03-29 at 10:19 +0200, Daniel Vetter wrote:
> On Wed, Mar 23, 2016 at 01:41:05PM +0000, Alexey Brodkin wrote:
> > 
> > Hi David,
> > 
> > On Wed, 2016-03-23 at 12:13 +0100, David Herrmann wrote:
> > > 
> > > Hi
> > > 
> > > On Wed, Mar 23, 2016 at 9:42 AM, Alexey Brodkin
> > > <Alexey.Brodkin@synopsys.com> wrote:
> > > > 
> > > > 
> > > > As a pair to already existing drm_connector_unregister_all() we're adding
> > > > generic implementation of what is already done in some drivers.
> > > > 
> > > > Once this helper is implemented we'll be ready to switch existing
> > > > driver-specific implementations with the generic one.
> > > > 
> > > > Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > Cc: David Airlie <airlied@linux.ie>
> > > > ---
> > > > 
> > > > Changes v2 -> v3:
> > > >  * Updated title with capital after colon
> > > >  * Simplified failure path with direct and unconditional invocation of
> > > >    unregister_all()
> > > >  * Updated kerneldoc description of the drm_connector_register_all()
> > > > 
> > > > Changes v1 -> v2:
> > > >  * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
> > > >  * Use drm_for_each_connector() instead of list_for_each_entry()
> > > >  * Updated kerneldoc for drm_dev_register()
> > > > 
> > > >  drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> > > >  drivers/gpu/drm/drm_drv.c  |  6 +++++-
> > > >  include/drm/drm_crtc.h     |  3 ++-
> > > >  3 files changed, 50 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > > > index 65488a6..21eea11 100644
> > > > --- a/drivers/gpu/drm/drm_crtc.c
> > > > +++ b/drivers/gpu/drm/drm_crtc.c
> > > > @@ -1081,6 +1081,49 @@ void drm_connector_unregister(struct drm_connector *connector)
> > > >  EXPORT_SYMBOL(drm_connector_unregister);
> > > > 
> > > >  /**
> > > > + * drm_connector_register_all - register all connectors
> > > > + * @dev: drm device
> > > > + *
> > > > + * This function registers all connectors in sysfs and other places so that
> > > > + * userspace can start to access them. Drivers can call it after calling
> > > > + * drm_dev_register() to complete the device registration, if they don't call
> > > > + * drm_connector_register() on each connector individually.
> > > > + *
> > > > + * When a device is unplugged and should be removed from userspace access,
> > > > + * call drm_connector_unregister_all(), which is the inverse of this
> > > > + * function.
> > > > + *
> > > > + * Returns:
> > > > + * Zero on success, error code on failure.
> > > > + */
> > > > +int drm_connector_register_all(struct drm_device *dev)
> > > > +{
> > > > +       struct drm_connector *connector;
> > > > +       int ret;
> > > > +
> > > > +       mutex_lock(&dev->mode_config.mutex);
> > > > +
> > > > +       drm_for_each_connector(connector, dev) {
> > > > +               ret = drm_connector_register(connector);
> > > > +               if (ret) {
> > > > +                       /*
> > > > +                        * We may safely call unregister_all() here within
> > > > +                        * area locked with mutex because unregister_all()
> > > > +                        * doesn't use locks inside (see a comment in that
> > > > +                        * function).
> > > > +                        */
> > > Ugh? unregister_all() says:
> > > 
> > > /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
> > > 
> > > This strongly contradicts your comment. Anyway, regardless how you
> > > want to fix it: You better unlock the mode-config mutex before
> > > returning below.
> > So good catch.
> > But what I really meant since we didn't get any further after registering
> > all "good" connections (see we're not releasing mutex still) the will be
> > no clashes with sysfs.
> > 
> > Still I;d like Daniel to comment on that separately.
> I think doing the unregister_all outside of the loop&locked section is
> better for future-proofing. My long-term plan for connector lifetimes and
> the connector list is:
> - refcounting for connectors (Dave has wip patches already).
> - separate lock for the connector list (and only that).
> 
> Doing it entirely separate would make things easier and more robust.

Ok makes sense.

> I merged patch 1 meanwhile to drm-misc.

So may I re-send only patches 2-4 then (using "drm-misc" as a base)?

-Alexey
Daniel Vetter March 29, 2016, 12:52 p.m. UTC | #5
On Tue, Mar 29, 2016 at 09:12:38AM +0000, Alexey Brodkin wrote:
> Hi Daniel,
> 
> On Tue, 2016-03-29 at 10:19 +0200, Daniel Vetter wrote:
> > On Wed, Mar 23, 2016 at 01:41:05PM +0000, Alexey Brodkin wrote:
> > > 
> > > Hi David,
> > > 
> > > On Wed, 2016-03-23 at 12:13 +0100, David Herrmann wrote:
> > > > 
> > > > Hi
> > > > 
> > > > On Wed, Mar 23, 2016 at 9:42 AM, Alexey Brodkin
> > > > <Alexey.Brodkin@synopsys.com> wrote:
> > > > > 
> > > > > 
> > > > > As a pair to already existing drm_connector_unregister_all() we're adding
> > > > > generic implementation of what is already done in some drivers.
> > > > > 
> > > > > Once this helper is implemented we'll be ready to switch existing
> > > > > driver-specific implementations with the generic one.
> > > > > 
> > > > > Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > Cc: David Airlie <airlied@linux.ie>
> > > > > ---
> > > > > 
> > > > > Changes v2 -> v3:
> > > > >  * Updated title with capital after colon
> > > > >  * Simplified failure path with direct and unconditional invocation of
> > > > >    unregister_all()
> > > > >  * Updated kerneldoc description of the drm_connector_register_all()
> > > > > 
> > > > > Changes v1 -> v2:
> > > > >  * Rename drm_connector_unplug_all() to drm_connector_unregister_all()
> > > > >  * Use drm_for_each_connector() instead of list_for_each_entry()
> > > > >  * Updated kerneldoc for drm_dev_register()
> > > > > 
> > > > >  drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> > > > >  drivers/gpu/drm/drm_drv.c  |  6 +++++-
> > > > >  include/drm/drm_crtc.h     |  3 ++-
> > > > >  3 files changed, 50 insertions(+), 2 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> > > > > index 65488a6..21eea11 100644
> > > > > --- a/drivers/gpu/drm/drm_crtc.c
> > > > > +++ b/drivers/gpu/drm/drm_crtc.c
> > > > > @@ -1081,6 +1081,49 @@ void drm_connector_unregister(struct drm_connector *connector)
> > > > >  EXPORT_SYMBOL(drm_connector_unregister);
> > > > > 
> > > > >  /**
> > > > > + * drm_connector_register_all - register all connectors
> > > > > + * @dev: drm device
> > > > > + *
> > > > > + * This function registers all connectors in sysfs and other places so that
> > > > > + * userspace can start to access them. Drivers can call it after calling
> > > > > + * drm_dev_register() to complete the device registration, if they don't call
> > > > > + * drm_connector_register() on each connector individually.
> > > > > + *
> > > > > + * When a device is unplugged and should be removed from userspace access,
> > > > > + * call drm_connector_unregister_all(), which is the inverse of this
> > > > > + * function.
> > > > > + *
> > > > > + * Returns:
> > > > > + * Zero on success, error code on failure.
> > > > > + */
> > > > > +int drm_connector_register_all(struct drm_device *dev)
> > > > > +{
> > > > > +       struct drm_connector *connector;
> > > > > +       int ret;
> > > > > +
> > > > > +       mutex_lock(&dev->mode_config.mutex);
> > > > > +
> > > > > +       drm_for_each_connector(connector, dev) {
> > > > > +               ret = drm_connector_register(connector);
> > > > > +               if (ret) {
> > > > > +                       /*
> > > > > +                        * We may safely call unregister_all() here within
> > > > > +                        * area locked with mutex because unregister_all()
> > > > > +                        * doesn't use locks inside (see a comment in that
> > > > > +                        * function).
> > > > > +                        */
> > > > Ugh? unregister_all() says:
> > > > 
> > > > /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
> > > > 
> > > > This strongly contradicts your comment. Anyway, regardless how you
> > > > want to fix it: You better unlock the mode-config mutex before
> > > > returning below.
> > > So good catch.
> > > But what I really meant since we didn't get any further after registering
> > > all "good" connections (see we're not releasing mutex still) the will be
> > > no clashes with sysfs.
> > > 
> > > Still I;d like Daniel to comment on that separately.
> > I think doing the unregister_all outside of the loop&locked section is
> > better for future-proofing. My long-term plan for connector lifetimes and
> > the connector list is:
> > - refcounting for connectors (Dave has wip patches already).
> > - separate lock for the connector list (and only that).
> > 
> > Doing it entirely separate would make things easier and more robust.
> 
> Ok makes sense.
> 
> > I merged patch 1 meanwhile to drm-misc.
> 
> So may I re-send only patches 2-4 then (using "drm-misc" as a base)?

Sure. drm-misc is also in linux-next, in case you need other bits to be
able to test all your patches.
-Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 65488a6..21eea11 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1081,6 +1081,49 @@  void drm_connector_unregister(struct drm_connector *connector)
 EXPORT_SYMBOL(drm_connector_unregister);
 
 /**
+ * drm_connector_register_all - register all connectors
+ * @dev: drm device
+ *
+ * This function registers all connectors in sysfs and other places so that
+ * userspace can start to access them. Drivers can call it after calling
+ * drm_dev_register() to complete the device registration, if they don't call
+ * drm_connector_register() on each connector individually.
+ *
+ * When a device is unplugged and should be removed from userspace access,
+ * call drm_connector_unregister_all(), which is the inverse of this
+ * function.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_connector_register_all(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+	int ret;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	drm_for_each_connector(connector, dev) {
+		ret = drm_connector_register(connector);
+		if (ret) {
+			/*
+			 * We may safely call unregister_all() here within
+			 * area locked with mutex because unregister_all()
+			 * doesn't use locks inside (see a comment in that
+			 * function).
+			 */
+			drm_connector_unregister_all(dev);
+			return ret;
+		}
+	}
+
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_register_all);
+
+/**
  * drm_connector_unregister_all - unregister connector userspace interfaces
  * @dev: drm device
  *
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 167c8d3..2c9a2b6 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -715,7 +715,11 @@  EXPORT_SYMBOL(drm_dev_unref);
  *
  * Register the DRM device @dev with the system, advertise device to user-space
  * and start normal device operation. @dev must be allocated via drm_dev_alloc()
- * previously.
+ * previously. Right after drm_dev_register() the driver should call
+ * drm_connector_register_all() to register all connectors in sysfs. This is
+ * a separate call for backward compatibility with drivers still using
+ * the deprecated ->load() callback, where connectors are registered from within
+ * the ->load() callback.
  *
  * Never call this twice on any device!
  *
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 42d9f4d..6a34117 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -2214,7 +2214,8 @@  void drm_connector_unregister(struct drm_connector *connector);
 
 extern void drm_connector_cleanup(struct drm_connector *connector);
 extern unsigned int drm_connector_index(struct drm_connector *connector);
-/* helper to unregister all connectors from sysfs for device */
+/* helpers to {un}register all connectors from sysfs for device */
+extern int drm_connector_register_all(struct drm_device *dev);
 extern void drm_connector_unregister_all(struct drm_device *dev);
 
 extern int drm_bridge_add(struct drm_bridge *bridge);