diff mbox series

[2/7] drm/dp_mst: Register AUX devices for MST ports

Message ID 1558019883-12397-3-git-send-email-sunpeng.li@amd.com (mailing list archive)
State New, archived
Headers show
Series Add DP MST AUX devices | expand

Commit Message

Leo Li May 16, 2019, 3:17 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

All available downstream ports - physical and logical - are exposed for
each MST device. They are listed in /dev/, following the same naming
scheme as SST devices by appending an incremental ID.

Although all downstream ports are exposed, only some will work as
expected. Consider the following topology:

               +---------+
               |  ASIC   |
               +---------+
              Conn-0|
                    |
               +----v----+
          +----| MST HUB |----+
          |    +---------+    |
          |                   |
          |Port-1       Port-2|
    +-----v-----+       +-----v-----+
    |  MST      |       |  SST      |
    |  Display  |       |  Display  |
    +-----------+       +-----------+
          |Port-1
          x

 MST Path  | MST Device
 ----------+----------------------------------
 sst:0     | MST Hub
 mst:0-1   | MST Display
 mst:0-1-1 | MST Display's disconnected DP out
 mst:0-1-8 | MST Display's internal sink
 mst:0-2   | SST Display

On certain MST displays, the upstream physical port will ACK DPCD reads.
However, reads on the local logical port to the internal sink will
*NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs.

There may also be duplicates. Some displays will return the same GUID
when reading DPCD from both mst:0-1 and mst:0-1-8.

There are some device-dependent behavior as well. The MST hub used
during testing will actually *ACK* read requests on a disconnected
physical port, whereas the MST displays will NAK.

In light of these discrepancies, it's simpler to expose all downstream
ports - both physical and logical - and let the user decide what to use.

Cc: Lyude Paul <lyude@redhat.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Leo Li <sunpeng.li@amd.com>
---
 drivers/gpu/drm/drm_dp_aux_dev.c      |  14 ++++-
 drivers/gpu/drm/drm_dp_mst_topology.c | 103 +++++++++++++++++++++++++++++-----
 include/drm/drm_dp_helper.h           |   4 ++
 include/drm/drm_dp_mst_helper.h       |   6 ++
 4 files changed, 112 insertions(+), 15 deletions(-)

Comments

Lyude Paul May 16, 2019, 9:40 p.m. UTC | #1
So a couple of things:

On Thu, 2019-05-16 at 11:17 -0400, sunpeng.li@amd.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> All available downstream ports - physical and logical - are exposed for
> each MST device. They are listed in /dev/, following the same naming
> scheme as SST devices by appending an incremental ID.
> 
> Although all downstream ports are exposed, only some will work as
> expected. Consider the following topology:
> 
>                +---------+
>                |  ASIC   |
>                +---------+
>               Conn-0|
>                     |
>                +----v----+
>           +----| MST HUB |----+
>           |    +---------+    |
>           |                   |
>           |Port-1       Port-2|
>     +-----v-----+       +-----v-----+
>     |  MST      |       |  SST      |
>     |  Display  |       |  Display  |
>     +-----------+       +-----------+
>           |Port-1
>           x
> 
>  MST Path  | MST Device
>  ----------+----------------------------------
>  sst:0     | MST Hub
>  mst:0-1   | MST Display
>  mst:0-1-1 | MST Display's disconnected DP out
>  mst:0-1-8 | MST Display's internal sink
>  mst:0-2   | SST Display
> 
> On certain MST displays, the upstream physical port will ACK DPCD reads.
> However, reads on the local logical port to the internal sink will
> *NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs.
> 
> There may also be duplicates. Some displays will return the same GUID
> when reading DPCD from both mst:0-1 and mst:0-1-8.
> 
> There are some device-dependent behavior as well. The MST hub used
> during testing will actually *ACK* read requests on a disconnected
> physical port, whereas the MST displays will NAK.
> 
> In light of these discrepancies, it's simpler to expose all downstream
> ports - both physical and logical - and let the user decide what to use.
> 
> Cc: Lyude Paul <lyude@redhat.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Leo Li <sunpeng.li@amd.com>
> ---
>  drivers/gpu/drm/drm_dp_aux_dev.c      |  14 ++++-
>  drivers/gpu/drm/drm_dp_mst_topology.c | 103 +++++++++++++++++++++++++++++
> -----
>  include/drm/drm_dp_helper.h           |   4 ++
>  include/drm/drm_dp_mst_helper.h       |   6 ++
>  4 files changed, 112 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c
> b/drivers/gpu/drm/drm_dp_aux_dev.c
> index 6d84611..01c02b9 100644
> --- a/drivers/gpu/drm/drm_dp_aux_dev.c
> +++ b/drivers/gpu/drm/drm_dp_aux_dev.c
> @@ -34,6 +34,7 @@
>  #include <linux/uaccess.h>
>  #include <linux/uio.h>
>  #include <drm/drm_dp_helper.h>
> +#include <drm/drm_dp_mst_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drmP.h>
>  
> @@ -114,6 +115,7 @@ static ssize_t name_show(struct device *dev,
>  
>  	return res;
>  }
> +
>  static DEVICE_ATTR_RO(name);
>  
>  static struct attribute *drm_dp_aux_attrs[] = {
> @@ -160,7 +162,11 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb,
> struct iov_iter *to)
>  			break;
>  		}
>  
> -		res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
> +		if (aux_dev->aux->is_remote)
> +			res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf,
> todo);
> +		else
> +			res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
> +

It's still not at all clear to me why we're trying to avoid specifying actual
callbacks for the aux device. We should remove this part entirely, remove the
is_remote entry from struct drm_dp_aux, and then just specify our own hook in
struct drm_dp_aux->transfer().

>  		if (res <= 0)
>  			break;
>  
> @@ -207,7 +213,11 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb,
> struct iov_iter *from)
>  			break;
>  		}
>  
> -		res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
> +		if (aux_dev->aux->is_remote)
> +			res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf,
> todo);
> +		else
> +			res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
> +
>  		if (res <= 0)
>  			break;
>  
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> b/drivers/gpu/drm/drm_dp_mst_topology.c
> index 2ab16c9..54da68e 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -35,6 +35,8 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
>  
> +#include "drm_crtc_helper_internal.h"
> +

Unless I'm mistaken, this looks like some sort of ditritus.

>  /**
>   * DOC: dp mst helper
>   *
> @@ -52,6 +54,9 @@ static int drm_dp_dpcd_write_payload(struct
> drm_dp_mst_topology_mgr *mgr,
>  				     int id,
>  				     struct drm_dp_payload *payload);
>  
> +static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
> +				 struct drm_dp_mst_port *port,
> +				 int offset, int size, u8 *bytes);
>  static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
>  				  struct drm_dp_mst_port *port,
>  				  int offset, int size, u8 *bytes);
> @@ -941,6 +946,8 @@ static void drm_dp_destroy_port(struct kref *kref)
>  	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
>  
>  	if (!port->input) {
> +		drm_dp_aux_unregister_devnode(&port->aux);
> +
>  		port->vcpi.num_slots = 0;
>  
>  		kfree(port->cached_edid);
> @@ -1095,6 +1102,46 @@ static bool drm_dp_port_setup_pdt(struct
> drm_dp_mst_port *port)
>  	return send_link;
>  }
>  
> +/**
> + * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via
> sideband
> + * @aux: Fake sideband AUX CH
> + * @offset: address of the (first) register to read
> + * @buffer: buffer to store the register values
> + * @size: number of bytes in @buffer
> + *
> + * Performs the same functionality for remote devices via
> + * sideband messaging as drm_dp_dpcd_read() does for local
> + * devices via actual AUX CH.
> + */
> +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
> +			     unsigned int offset, void *buffer, size_t size)
> +{
> +	struct drm_dp_mst_port *port = container_of(aux, struct
> drm_dp_mst_port, aux);
> +
> +	return drm_dp_send_dpcd_read(port->mgr, port,
> +				     offset, size, buffer);
> +}
> +
> +/**
> + * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via
> sideband
> + * @aux: Fake sideband AUX CH
> + * @offset: address of the (first) register to write
> + * @buffer: buffer containing the values to write
> + * @size: number of bytes in @buffer
> + *
> + * Performs the same functionality for remote devices via
> + * sideband messaging as drm_dp_dpcd_write() does for local
> + * devices via actual AUX CH.
> + */
> +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
> +			      unsigned int offset, void *buffer, size_t size)
> +{
> +	struct drm_dp_mst_port *port = container_of(aux, struct
> drm_dp_mst_port, aux);
> +
> +	return drm_dp_send_dpcd_write(port->mgr, port,
> +				      offset, size, buffer);
> +}
> +
>  static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8
> *guid)
>  {
>  	int ret;
> @@ -1158,6 +1205,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
> *mstb,
>  		port->mgr = mstb->mgr;
>  		port->aux.name = "DPMST";
>  		port->aux.dev = dev->dev;
> +		port->aux.is_remote = true;
>  		created = true;
>  	} else {
>  		old_pdt = port->pdt;
> @@ -1188,7 +1236,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
> *mstb,
>  				drm_dp_send_enum_path_resources(mstb->mgr,
> mstb, port);
>  		} else {
>  			port->available_pbn = 0;
> -			}
> +		}
>  	}
>  
>  	if (old_pdt != port->pdt && !port->input) {
> @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
> *mstb,
>  			drm_connector_set_tile_property(port->connector);
>  		}
>  		(*mstb->mgr->cbs->register_connector)(port->connector);

This is wrong: we always want to setup everything in the connector first
before trying to register it, not after. Otherwise, things explode like so:

[   13.305329] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
[   13.305361] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
[   13.305384] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
[   13.305405] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
[   13.305429] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
[   13.305449] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
[   13.305471] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
[   13.305490] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
[   13.305512] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
[   13.305532] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
[   13.305552] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
[   13.305571] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
[   13.305592] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
[   13.305612] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
[   13.305631] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
[   13.305651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
[   13.305725] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 0, ret: 0
[   13.305768] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 1, ret: 0
[   13.306088] [drm:drm_handle_vblank [drm]] vblank event on 325, current 325
[   13.322514] [drm:drm_handle_vblank [drm]] vblank event on 313, current 313
[   13.322612] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
[   13.322634] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
[   13.322656] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
[   13.322676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
[   13.322697] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
[   13.322718] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
[   13.322740] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
[   13.322764] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 0
[   13.322784] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
[   13.339191] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 1
[  451.149789] Console: switching to colour dummy device 80x25
[  451.194596] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-A] unregistering
[  451.194666] [drm:drm_sysfs_connector_remove [drm]] removing "eDP-1" from sysfs
[  451.194718] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-B] unregistering
[  451.194766] [drm:drm_sysfs_connector_remove [drm]] removing "DP-1" from sysfs
[  451.194791] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-1" from sysfs
[  451.194835] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-C] unregistering
[  451.194880] [drm:drm_sysfs_connector_remove [drm]] removing "DP-2" from sysfs
[  451.194903] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-2" from sysfs
[  451.194924] [drm:drm_sysfs_connector_remove [drm]] removing "DP-3" from sysfs
[  451.194950] [drm:drm_sysfs_connector_remove [drm]] removing "DP-4" from sysfs
[  451.194975] [drm:drm_sysfs_connector_remove [drm]] removing "DP-5" from sysfs
[  451.204535] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
[  451.204551] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
[  451.204566] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
[  451.204582] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
[  451.204596] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
[  451.204611] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
[  451.204621] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
[  451.204631] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
[  451.204641] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
[  451.204651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
[  451.204662] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
[  451.204671] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
[  451.204680] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
[  451.204689] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
[  451.204699] [drm:drm_dp_mst_duplicate_state [drm_kms_helper]] port 00000000dde1b00a (5)
[  451.204703] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (4)
[  451.411817] [drm:intel_panel_actually_set_backlight [i915]] set backlight PWM = 0
[  451.420911] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-A: 0x00600 AUX <- (ret=  1) 02
[  451.425358] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x11101010, pins 0x00000010, long 0x00000000
[  451.425422] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - short
[  451.471777] [drm:drm_dp_mst_topology_get_mstb_validated [drm_kms_helper]] mstb 00000000eec1a629 (2)
[  451.473361] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
[  451.473465] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - long
[  452.207301] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
[  452.207395] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - long
[  452.340311] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00000 AUX -> (ret= 15) 11 0a 02 41 00 00 01 00 02 00 00 00 00 0b 00
[  452.341060] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00201 AUX -> (ret=  1) 00
[  452.341584] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000 AUX <- (ret= 10) 10 47 d3 11 11 01 00 00 00 f4
[  452.343183] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
[  452.343286] [drm:intel_hpd_irq_handler [i915]] digital hpd port B - short
[  452.344765] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
[  452.346263] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400 AUX -> (ret= 16) 10 46 d6 11 10 01 00 00 78 00 00 00 00 00 00 00
[  452.346287] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb 00000000eec1a629 (3)
[  452.346305] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (2)
[  452.346405] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (1)
[  452.347529] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003 AUX <- (ret=  3) 10 00 00
[  452.348672] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x002c0 AUX <- (ret=  1) 01
[  452.350168] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 77 77 01 00
[  452.351328] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x001c0 AUX <- (ret=  3) 01 01 00
[  452.352665] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
[  452.358905] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
[  452.360327] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
[  452.361660] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 03
[  452.361681] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (3)
[  452.361700] [drm:drm_dp_mst_topology_get_port_validated [drm_kms_helper]] port 00000000dde1b00a (2)
[  452.362894] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000 AUX <- (ret=  6) 10 43 c7 25 10 c0
[  452.364318] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
[  452.364421] [drm:intel_hpd_irq_handler [i915]] digital hpd port B - short
[  452.365929] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
[  452.367361] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400 AUX -> (ret= 16) 10 43 c7 25 10 c0 00 00 00 00 00 00 00 00 00 00
[  452.367388] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb 00000000eec1a629 (2)
[  452.367407] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (1)
[  452.367460] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000dde1b00a (1)
[  452.368548] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003 AUX <- (ret=  3) 10 00 00
[  452.368803] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00600 AUX <- (ret=  1) 02
[  452.368970] [drm:intel_dump_cdclk_state [i915]] Changing CDCLK to 337500 kHz, VCO 8100000 kHz, ref 24000 kHz, bypass 24000 kHz, voltage level 0
[  452.369269] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (1)
[  452.369330] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (1)
[  452.369422] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
[  452.369466] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (4)
[  452.369515] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
[  452.369558] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (4)
[  452.369608] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (3)
[  452.369660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (2)
[  452.369690] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (2)
[  452.369750] [drm:drm_irq_uninstall [drm]] irq=177
[  452.406452] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 00 00 80 00
[  452.412626] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (3)
[  452.412636] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 91 (2)
[  452.412644] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 98 (2)
[  452.412652] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 104 (2)
[  452.412660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 109 (2)
[  452.412668] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (3)
[  452.412676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (2)
[  452.412684] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (2)
[  452.412692] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (2)
[  452.412700] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (2)
[  452.412708] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (1)
[  452.424450] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00111 AUX <- (ret=  1) 00
[  452.424454] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (0)
[  452.424457] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000eeef3cfd (0)
[  452.424461] ------------[ cut here ]------------
[  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
[  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
[  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G           O      5.1.0Lyude-Test+ #1
[  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
[  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
[  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
[  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
[  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
[  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
[  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09: 0000000000000046
[  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd5f77010
[  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15: dead000000000100
[  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
[  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
[  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  452.424512] Call Trace:
[  452.424516]  device_del+0x75/0x360
[  452.424518]  ? class_find_device+0x96/0xf0
[  452.424520]  device_unregister+0x16/0x60
[  452.424521]  device_destroy+0x3a/0x40
[  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
[  452.424534]  ? drm_dbg+0x87/0x90 [drm]
[  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
[  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
[  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
[  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
[  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
[  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
[  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
[  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
[  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
[  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
[  452.424647]  pci_device_remove+0x3b/0xc0
[  452.424649]  device_release_driver_internal+0xe4/0x1d0
[  452.424651]  pci_stop_bus_device+0x69/0x90
[  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
[  452.424655]  remove_store+0x75/0x90
[  452.424656]  kernfs_fop_write+0x116/0x190
[  452.424658]  vfs_write+0xa5/0x1a0
[  452.424660]  ksys_write+0x57/0xd0
[  452.424663]  do_syscall_64+0x55/0x150
[  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  452.424667] RIP: 0033:0x7f8cc1e7d038
[  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
[  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
[  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
[  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
[  452.424675] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
[  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
[  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.424680] ---[ end trace a1c11eaf054910a3 ]---
[  452.424751] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
[  452.424755] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 000000000f6aa5a3 (0)
[  452.424765] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (1)
[  452.424770] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000eeef3cfd (1)
[  452.424773] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000eeef3cfd (0)
[  452.424776] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (4)
[  452.424783] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug event
[  452.424790] ------------[ cut here ]------------
[  452.424791] sysfs group 'power' not found for kobject 'drm_dp_aux4'
[  452.424795] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.424796] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
[  452.424809] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G        W  O      5.1.0Lyude-Test+ #1
[  452.424811] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
[  452.424812] RIP: 0010:sysfs_remove_group+0x76/0x80
[  452.424813] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
[  452.424815] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
[  452.424816] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
[  452.424817] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
[  452.424818] RBP: ffffffffa9ea12e0 R08: 00000000000007d1 R09: 0000000000000046
[  452.424820] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd50d0410
[  452.424821] R13: ffff981fd6ebbebc R14: dead000000000200 R15: dead000000000100
[  452.424822] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
[  452.424823] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  452.424824] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
[  452.424825] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  452.424826] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  452.424827] Call Trace:
[  452.424829]  device_del+0x75/0x360
[  452.424830]  ? class_find_device+0x96/0xf0
[  452.424832]  device_unregister+0x16/0x60
[  452.424833]  device_destroy+0x3a/0x40
[  452.424837]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
[  452.424841]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
[  452.424845]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
[  452.424849]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
[  452.424854]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
[  452.424873]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
[  452.424892]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
[  452.424900]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
[  452.424920]  intel_modeset_cleanup+0xc8/0x140 [i915]
[  452.424932]  i915_driver_unload+0xa8/0x130 [i915]
[  452.424943]  i915_pci_remove+0x1e/0x40 [i915]
[  452.424945]  pci_device_remove+0x3b/0xc0
[  452.424947]  device_release_driver_internal+0xe4/0x1d0
[  452.424948]  pci_stop_bus_device+0x69/0x90
[  452.424950]  pci_stop_and_remove_bus_device_locked+0x16/0x30
[  452.424951]  remove_store+0x75/0x90
[  452.424953]  kernfs_fop_write+0x116/0x190
[  452.424954]  vfs_write+0xa5/0x1a0
[  452.424956]  ksys_write+0x57/0xd0
[  452.424957]  do_syscall_64+0x55/0x150
[  452.424959]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  452.424960] RIP: 0033:0x7f8cc1e7d038
[  452.424961] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
[  452.424963] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[  452.424965] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
[  452.424966] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
[  452.424967] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
[  452.424968] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
[  452.424969] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
[  452.424971] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.424972] ---[ end trace a1c11eaf054910a4 ]---
[  452.424992] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
[  452.424997] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000dde1b00a (0)
[  452.425006] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (1)
[  452.425010] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000000f6aa5a3 (1)
[  452.425014] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000000f6aa5a3 (0)
[  452.425017] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (3)
[  452.425023] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug event
[  452.425028] ------------[ cut here ]------------
[  452.425029] sysfs group 'power' not found for kobject 'drm_dp_aux3'
[  452.425033] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.425034] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
[  452.425047] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G        W  O      5.1.0Lyude-Test+ #1
[  452.425048] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
[  452.425050] RIP: 0010:sysfs_remove_group+0x76/0x80
[  452.425051] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
[  452.425053] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
[  452.425054] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
[  452.425055] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
[  452.425056] RBP: ffffffffa9ea12e0 R08: 000000000000080f R09: 0000000000000046
[  452.425057] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd50d1810
[  452.425058] R13: ffff981fd6ebbe1c R14: dead000000000200 R15: dead000000000100
[  452.425059] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
[  452.425061] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  452.425062] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
[  452.425063] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  452.425064] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  452.425065] Call Trace:
[  452.425066]  device_del+0x75/0x360
[  452.425068]  ? class_find_device+0x96/0xf0
[  452.425069]  device_unregister+0x16/0x60
[  452.425070]  device_destroy+0x3a/0x40
[  452.425074]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
[  452.425078]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
[  452.425083]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
[  452.425087]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
[  452.425091]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
[  452.425110]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
[  452.425128]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
[  452.425137]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
[  452.425157]  intel_modeset_cleanup+0xc8/0x140 [i915]
[  452.425168]  i915_driver_unload+0xa8/0x130 [i915]
[  452.425180]  i915_pci_remove+0x1e/0x40 [i915]
[  452.425182]  pci_device_remove+0x3b/0xc0
[  452.425183]  device_release_driver_internal+0xe4/0x1d0
[  452.425185]  pci_stop_bus_device+0x69/0x90
[  452.425186]  pci_stop_and_remove_bus_device_locked+0x16/0x30
[  452.425188]  remove_store+0x75/0x90
[  452.425189]  kernfs_fop_write+0x116/0x190
[  452.425191]  vfs_write+0xa5/0x1a0
[  452.425192]  ksys_write+0x57/0xd0
[  452.425194]  do_syscall_64+0x55/0x150
[  452.425195]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  452.425197] RIP: 0033:0x7f8cc1e7d038
[  452.425198] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
[  452.425199] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[  452.425201] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
[  452.425202] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
[  452.425203] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
[  452.425204] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
[  452.425205] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
[  452.425207] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
[  452.425208] ---[ end trace a1c11eaf054910a5 ]---
[  452.425282] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
[  452.425288] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 000000002ba3174e (0)
[  452.425292] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000002ba3174e (0)
[  452.425295] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (2)
[  452.425299] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (1)
[  452.425311] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (1)
[  452.425318] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (1)
[  452.425365] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (0)
[  452.425368] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (0)

So, we need to move the drm_dp_aux_register_devnode() call above the connector
registration callback. Same goes for the port->aux.dev = port->connector-
>kdev; assignment that you do in patch 3/7 (and of course, you can remove the
connector registration status check there now).

> +
> +		drm_dp_aux_register_devnode(&port->aux);
>  	}
>  
>  out:
> @@ -1404,7 +1454,6 @@ static bool drm_dp_validate_guid(struct
> drm_dp_mst_topology_mgr *mgr,
>  	return false;
>  }
>  
> -#if 0
>  static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num,
> u32 offset, u8 num_bytes)
>  {
>  	struct drm_dp_sideband_msg_req_body req;
> @@ -1417,7 +1466,6 @@ static int build_dpcd_read(struct
> drm_dp_sideband_msg_tx *msg, u8 port_num, u32
>  
>  	return 0;
>  }
> -#endif
>  
>  static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr,
>  				    bool up, u8 *msg, int len)
> @@ -1994,26 +2042,55 @@ int drm_dp_update_payload_part2(struct
> drm_dp_mst_topology_mgr *mgr)
>  }
>  EXPORT_SYMBOL(drm_dp_update_payload_part2);
>  
> -#if 0 /* unused as of yet */
>  static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
>  				 struct drm_dp_mst_port *port,
> -				 int offset, int size)
> +				 int offset, int size, u8 *bytes)
>  {
>  	int len;
> +	int ret = 0;
>  	struct drm_dp_sideband_msg_tx *txmsg;
> +	struct drm_dp_mst_branch *mstb;
> +
> +	mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
> +	if (!mstb)
> +		return -EINVAL;
>  
>  	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
> -	if (!txmsg)
> -		return -ENOMEM;
> +	if (!txmsg) {
> +		ret = -ENOMEM;
> +		goto fail_put;
> +	}
>  
> -	len = build_dpcd_read(txmsg, port->port_num, 0, 8);
> +	len = build_dpcd_read(txmsg, port->port_num, offset, size);
>  	txmsg->dst = port->parent;
>  
>  	drm_dp_queue_down_tx(mgr, txmsg);
>  
> -	return 0;
> +	ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
> +	if (ret < 0)
> +		goto fail_free;
> +
> +	/* DPCD read should never be NACKed */
> +	if (WARN_ON_ONCE(txmsg->reply.reply_type == 1)) {
> +		ret = -EIO;
> +		goto fail_free;
> +	}
> +
> +	if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) {
> +		ret = -EPROTO;
> +		goto fail_free;
> +	}
> +
> +	ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes,
> size);
> +	memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret);
> +
> +fail_free:
> +	kfree(txmsg);
> +fail_put:
> +	drm_dp_put_mst_branch_device(mstb);
> +
> +	return ret;
>  }
> -#endif
>  
>  static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
>  				  struct drm_dp_mst_port *port,
> @@ -2041,9 +2118,9 @@ static int drm_dp_send_dpcd_write(struct
> drm_dp_mst_topology_mgr *mgr,
>  
>  	ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
>  	if (ret > 0) {
> -		if (txmsg->reply.reply_type == 1) {
> -			ret = -EINVAL;
> -		} else
> +		if (txmsg->reply.reply_type == 1)
> +			ret = -EIO;
> +		else
>  			ret = 0;
>  	}
>  	kfree(txmsg);
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index 509667e..6dea76a 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -1265,6 +1265,10 @@ struct drm_dp_aux {
>  	 * @cec: struct containing fields used for CEC-Tunneling-over-AUX.
>  	 */
>  	struct drm_dp_aux_cec cec;
> +	/**
> +	 * @is_remote: Is this "AUX CH" actually using sideband messaging.
> +	 */
> +	bool is_remote;
>  };
>  
>  ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
> diff --git a/include/drm/drm_dp_mst_helper.h
> b/include/drm/drm_dp_mst_helper.h
> index 371cc28..30f8c11 100644
> --- a/include/drm/drm_dp_mst_helper.h
> +++ b/include/drm/drm_dp_mst_helper.h
> @@ -615,6 +615,12 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
>  
>  void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr);
>  int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
> +
> +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
> +			     unsigned int offset, void *buffer, size_t size);
> +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
> +			      unsigned int offset, void *buffer, size_t size);
> +
>  struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct
> drm_atomic_state *state,
>  								    struct
> drm_dp_mst_topology_mgr *mgr);
>  int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
Leo Li May 30, 2019, 6:20 p.m. UTC | #2
Hey, sorry for my late response!

On 2019-05-16 5:40 p.m., Lyude Paul wrote:

>>        if (old_pdt != port->pdt && !port->input) {
>> @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
>> *mstb,
>>                        drm_connector_set_tile_property(port->connector);
>>                }
>>                (*mstb->mgr->cbs->register_connector)(port->connector);
> This is wrong: we always want to setup everything in the connector first
> before trying to register it, not after. Otherwise, things explode like so:

**snip**

> [  452.424461] ------------[ cut here ]------------
> [  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
> [  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
> [  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G           O      5.1.0Lyude-Test+ #1
> [  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
> [  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
> [  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> [  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> [  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
> [  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
> [  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09: 0000000000000046
> [  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd5f77010
> [  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15: dead000000000100
> [  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
> [  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
> [  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [  452.424512] Call Trace:
> [  452.424516]  device_del+0x75/0x360
> [  452.424518]  ? class_find_device+0x96/0xf0
> [  452.424520]  device_unregister+0x16/0x60
> [  452.424521]  device_destroy+0x3a/0x40
> [  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> [  452.424534]  ? drm_dbg+0x87/0x90 [drm]
> [  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> [  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> [  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
> [  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> [  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> [  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> [  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> [  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
> [  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
> [  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
> [  452.424647]  pci_device_remove+0x3b/0xc0
> [  452.424649]  device_release_driver_internal+0xe4/0x1d0
> [  452.424651]  pci_stop_bus_device+0x69/0x90
> [  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> [  452.424655]  remove_store+0x75/0x90
> [  452.424656]  kernfs_fop_write+0x116/0x190
> [  452.424658]  vfs_write+0xa5/0x1a0
> [  452.424660]  ksys_write+0x57/0xd0
> [  452.424663]  do_syscall_64+0x55/0x150
> [  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [  452.424667] RIP: 0033:0x7f8cc1e7d038
> [  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> [  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
> [  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
> [  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
> [  452.424675] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
> [  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
> [  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424680] ---[ end trace a1c11eaf054910a3 ]---

**snip**

> 
> So, we need to move the drm_dp_aux_register_devnode() call above the connector
> registration callback. Same goes for the port->aux.dev = port->connector-
>> kdev; assignment that you do in patch 3/7 (and of course, you can remove the
> connector registration status check there now).

Hmm, I don't think that will quite work for the purpose of the series.

If I register the aux device before the connector's, I wouldn't be able
to set the connector's kdev as parent. The udev rules depend on this
hierarchy to generate the symlinks we want - it reads the parent
connector's attrs.

How are you reproducing this? I can try debugging this on an intel
system. It looks like there's an expected 'power' attribute group that's
missing when unregistering the aux device - I wonder where that gets
attached.

Thanks,
Leo

> 
>> +
>> +             drm_dp_aux_register_devnode(&port->aux);
>>        }
Lyude Paul June 3, 2019, 7:25 p.m. UTC | #3
On Thu, 2019-05-30 at 18:20 +0000, Li, Sun peng (Leo) wrote:
> Hey, sorry for my late response!
> 
> On 2019-05-16 5:40 p.m., Lyude Paul wrote:
> 
> > >        if (old_pdt != port->pdt && !port->input) {
> > > @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct
> > > drm_dp_mst_branch
> > > *mstb,
> > >                        drm_connector_set_tile_property(port->connector);
> > >                }
> > >                (*mstb->mgr->cbs->register_connector)(port->connector);
> > This is wrong: we always want to setup everything in the connector first
> > before trying to register it, not after. Otherwise, things explode like
> > so:
> 
> **snip**
> 
> > [  452.424461] ------------[ cut here ]------------
> > [  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
> > [  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl
> > x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm
> > mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof
> > intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel
> > intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl
> > btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth
> > drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801
> > intel_xhci_usb_role_switch processor_thermal_device typec_ucsi
> > intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec
> > intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal
> > int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video
> > pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage
> > i2c_dev
> > [  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted:
> > G           O      5.1.0Lyude-Test+ #1
> > [  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W
> > (1.12 ) 04/09/2018
> > [  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
> > [  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc
> > ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff
> > <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> > [  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> > [  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX:
> > 0000000000000006
> > [  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI:
> > ffff981fde2d5a00
> > [  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09:
> > 0000000000000046
> > [  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12:
> > ffff981fd5f77010
> > [  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15:
> > dead000000000100
> > [  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000)
> > knlGS:0000000000000000
> > [  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4:
> > 00000000003606e0
> > [  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> > 0000000000000000
> > [  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> > 0000000000000400
> > [  452.424512] Call Trace:
> > [  452.424516]  device_del+0x75/0x360
> > [  452.424518]  ? class_find_device+0x96/0xf0
> > [  452.424520]  device_unregister+0x16/0x60
> > [  452.424521]  device_destroy+0x3a/0x40
> > [  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> > [  452.424534]  ? drm_dbg+0x87/0x90 [drm]
> > [  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> > [  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> > [  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0
> > [drm_kms_helper]
> > [  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> > [  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> > [  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> > [  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> > [  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
> > [  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
> > [  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
> > [  452.424647]  pci_device_remove+0x3b/0xc0
> > [  452.424649]  device_release_driver_internal+0xe4/0x1d0
> > [  452.424651]  pci_stop_bus_device+0x69/0x90
> > [  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> > [  452.424655]  remove_store+0x75/0x90
> > [  452.424656]  kernfs_fop_write+0x116/0x190
> > [  452.424658]  vfs_write+0xa5/0x1a0
> > [  452.424660]  ksys_write+0x57/0xd0
> > [  452.424663]  do_syscall_64+0x55/0x150
> > [  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > [  452.424667] RIP: 0033:0x7f8cc1e7d038
> > [  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00
> > f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05
> > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> > [  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000001
> > [  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX:
> > 00007f8cc1e7d038
> > [  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI:
> > 0000000000000001
> > [  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09:
> > 00007f8cc1f0ee80
> > [  452.424675] R10: 000000000000000a R11: 0000000000000246 R12:
> > 00007f8cc1f50780
> > [  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15:
> > 0000000000000002
> > [  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424680] ---[ end trace a1c11eaf054910a3 ]---
> 
> **snip**
> 
> > So, we need to move the drm_dp_aux_register_devnode() call above the
> > connector
> > registration callback. Same goes for the port->aux.dev = port->connector-
> > > kdev; assignment that you do in patch 3/7 (and of course, you can remove
> > > the
> > connector registration status check there now).
> 
> Hmm, I don't think that will quite work for the purpose of the series.
> 
> If I register the aux device before the connector's, I wouldn't be able
> to set the connector's kdev as parent. The udev rules depend on this
> hierarchy to generate the symlinks we want - it reads the parent
> connector's attrs.

eesh, you're right-somehow I didn't notice that. Guess we'll need some sort of
other fix then

> 
> How are you reproducing this? I can try debugging this on an intel
> system. It looks like there's an expected 'power' attribute group that's
> missing when unregistering the aux device - I wonder where that gets
> attached.

I'm reproducing this just by reloading i915 on a machine with some MST
displays connected. I uploaded a copy of the script that I use to do this
here:

https://people.freedesktop.org/~lyudess/archive/06-03-2019/unloadgpumod.sh

Given a module (in this case drm.ko), it will go through and unload all of the
modules depending on it, then drm.ko, then reload.
> 
> Thanks,
> Leo
> 
> > > +
> > > +             drm_dp_aux_register_devnode(&port->aux);
> > >        }
Lyude Paul June 3, 2019, 7:28 p.m. UTC | #4
On Mon, 2019-06-03 at 15:25 -0400, Lyude Paul wrote:
> On Thu, 2019-05-30 at 18:20 +0000, Li, Sun peng (Leo) wrote:
> > Hey, sorry for my late response!
> > 
> > On 2019-05-16 5:40 p.m., Lyude Paul wrote:
> > 
> > > >        if (old_pdt != port->pdt && !port->input) {
> > > > @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct
> > > > drm_dp_mst_branch
> > > > *mstb,
> > > >                        drm_connector_set_tile_property(port-
> > > > >connector);
> > > >                }
> > > >                (*mstb->mgr->cbs->register_connector)(port->connector);
> > > This is wrong: we always want to setup everything in the connector first
> > > before trying to register it, not after. Otherwise, things explode like
> > > so:
> > 
> > **snip**
> > 
> > > [  452.424461] ------------[ cut here ]------------
> > > [  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
> > > [  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > > sysfs_remove_group+0x76/0x80
> > > [  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl
> > > x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm
> > > mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof
> > > intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel
> > > intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl
> > > btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth
> > > drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801
> > > intel_xhci_usb_role_switch processor_thermal_device typec_ucsi
> > > intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec
> > > intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal
> > > int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video
> > > pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage
> > > i2c_dev
> > > [  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted:
> > > G           O      5.1.0Lyude-Test+ #1
> > > [  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS
> > > N22ET35W
> > > (1.12 ) 04/09/2018
> > > [  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
> > > [  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0
> > > bc
> > > ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff
> > > <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> > > [  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> > > [  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX:
> > > 0000000000000006
> > > [  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI:
> > > ffff981fde2d5a00
> > > [  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09:
> > > 0000000000000046
> > > [  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12:
> > > ffff981fd5f77010
> > > [  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15:
> > > dead000000000100
> > > [  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000)
> > > knlGS:0000000000000000
> > > [  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > [  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4:
> > > 00000000003606e0
> > > [  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> > > 0000000000000000
> > > [  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> > > 0000000000000400
> > > [  452.424512] Call Trace:
> > > [  452.424516]  device_del+0x75/0x360
> > > [  452.424518]  ? class_find_device+0x96/0xf0
> > > [  452.424520]  device_unregister+0x16/0x60
> > > [  452.424521]  device_destroy+0x3a/0x40
> > > [  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180
> > > [drm_kms_helper]
> > > [  452.424534]  ? drm_dbg+0x87/0x90 [drm]
> > > [  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> > > [  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> > > [  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0
> > > [drm_kms_helper]
> > > [  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0
> > > [drm_kms_helper]
> > > [  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> > > [  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> > > [  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> > > [  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
> > > [  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
> > > [  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
> > > [  452.424647]  pci_device_remove+0x3b/0xc0
> > > [  452.424649]  device_release_driver_internal+0xe4/0x1d0
> > > [  452.424651]  pci_stop_bus_device+0x69/0x90
> > > [  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> > > [  452.424655]  remove_store+0x75/0x90
> > > [  452.424656]  kernfs_fop_write+0x116/0x190
> > > [  452.424658]  vfs_write+0xa5/0x1a0
> > > [  452.424660]  ksys_write+0x57/0xd0
> > > [  452.424663]  do_syscall_64+0x55/0x150
> > > [  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > > [  452.424667] RIP: 0033:0x7f8cc1e7d038
> > > [  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00
> > > 00
> > > f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05
> > > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> > > [  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX:
> > > 0000000000000001
> > > [  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX:
> > > 00007f8cc1e7d038
> > > [  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI:
> > > 0000000000000001
> > > [  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09:
> > > 00007f8cc1f0ee80
> > > [  452.424675] R10: 000000000000000a R11: 0000000000000246 R12:
> > > 00007f8cc1f50780
> > > [  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15:
> > > 0000000000000002
> > > [  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > > sysfs_remove_group+0x76/0x80
> > > [  452.424680] ---[ end trace a1c11eaf054910a3 ]---
> > 
> > **snip**
> > 
> > > So, we need to move the drm_dp_aux_register_devnode() call above the
> > > connector
> > > registration callback. Same goes for the port->aux.dev = port-
> > > >connector-
> > > > kdev; assignment that you do in patch 3/7 (and of course, you can
> > > > remove
> > > > the
> > > connector registration status check there now).
> > 
> > Hmm, I don't think that will quite work for the purpose of the series.
> > 
> > If I register the aux device before the connector's, I wouldn't be able
> > to set the connector's kdev as parent. The udev rules depend on this
> > hierarchy to generate the symlinks we want - it reads the parent
> > connector's attrs.
> 
> eesh, you're right-somehow I didn't notice that. Guess we'll need some sort
> of
> other fix then
> 
> > How are you reproducing this? I can try debugging this on an intel
> > system. It looks like there's an expected 'power' attribute group that's
> > missing when unregistering the aux device - I wonder where that gets
> > attached.
> 
> I'm reproducing this just by reloading i915 on a machine with some MST
> displays connected. I uploaded a copy of the script that I use to do this
> here:
> 
> https://people.freedesktop.org/~lyudess/archive/06-03-2019/unloadgpumod.sh

oops-almost forgot to mention. The argument you pass to make it reload instead
of just unloading is --reload

> 
> Given a module (in this case drm.ko), it will go through and unload all of
> the
> modules depending on it, then drm.ko, then reload.
> > Thanks,
> > Leo
> > 
> > > > +
> > > > +             drm_dp_aux_register_devnode(&port->aux);
> > > >        }
Leo Li June 6, 2019, 7:41 p.m. UTC | #5
On 2019-06-03 3:28 p.m., Lyude Paul wrote:
>> I'm reproducing this just by reloading i915 on a machine with some MST
>> displays connected. I uploaded a copy of the script that I use to do this
>> here:
>>
>> https://people.freedesktop.org/~lyudess/archive/06-03-2019/unloadgpumod.sh
> oops-almost forgot to mention. The argument you pass to make it reload instead
> of just unloading is --reload
> 

Thanks for the script!

So, the warning has to do with:

1. Having the aux device as a child of connector device, and
2. During driver unload, drm_connector_unregister() is called before
    drm_dp_mst_topology_put_port()

Which means that connector_unregister() will recursively remove the
child aux device, before put_port() can properly unregister it. Any
further attempts to remove after the first will throw a "not found" warning.

Call-stacks for reference:

   *drm_connector_unregister*+0x37/0x60 [drm]
   drm_connector_unregister_all+0x30/0x60 [drm]
   drm_modeset_unregister_all+0xe/0x30 [drm]
   drm_dev_unregister+0x9c/0xb0 [drm]
   i915_driver_unload+0x73/0x120 [i915]

   drm_dp_aux_unregister_devnode+0xf5/0x180 [drm_kms_helper]
   *drm_dp_mst_topology_put_port*+0x4e/0xf0 [drm_kms_helper]
   drm_dp_mst_topology_put_mstb+0x91/0x160 [drm_kms_helper]
   drm_dp_mst_topology_mgr_set_mst+0x12b/0x2b0 [drm_kms_helper]
   ? __finish_swait+0x10/0x40
   drm_dp_mst_topology_mgr_destroy+0x11/0xa0 [drm_kms_helper]
   intel_dp_encoder_flush_work+0x32/0xb0 [i915]
   intel_ddi_encoder_destroy+0x32/0x60 [i915]
   drm_mode_config_cleanup+0x51/0x2e0 [drm]
   intel_modeset_cleanup+0xc8/0x140 [i915]
   i915_driver_unload+0xa0/0x120 [i915]

A solution is to unregister the aux device immediately before the
connector device is unregistered - if we are to keep the aux device as a
child. Following current scheme with SST, it looks like
drm_connector_funcs->early_unregister() is the right place to do so.
To keep the balance, aux registration will then happen in
drm_connector_funcs->late_register(). This will leave the SDP
transaction handling part in DRM still, but pass the responsibility of
creating and removing remote (fake) aux devices to the driver.

I have a WIP patch here for you to take a look. It should apply on top
of the existing patchset:
https://pastebin.com/1YJZhL4C

I'd like to hear your thoughts, before I go and modify other drivers :)

Thanks,
Leo
Lyude Paul June 6, 2019, 9:07 p.m. UTC | #6
On Thu, 2019-06-06 at 19:41 +0000, Li, Sun peng (Leo) wrote:
> 
> On 2019-06-03 3:28 p.m., Lyude Paul wrote:
> > > I'm reproducing this just by reloading i915 on a machine with some MST
> > > displays connected. I uploaded a copy of the script that I use to do
> > > this
> > > here:
> > > 
> > > https://people.freedesktop.org/~lyudess/archive/06-03-2019/unloadgpumod.sh
> > oops-almost forgot to mention. The argument you pass to make it reload
> > instead
> > of just unloading is --reload
> > 
> 
> Thanks for the script!
> 
> So, the warning has to do with:
> 
> 1. Having the aux device as a child of connector device, and
> 2. During driver unload, drm_connector_unregister() is called before
>     drm_dp_mst_topology_put_port()
> 
> Which means that connector_unregister() will recursively remove the
> child aux device, before put_port() can properly unregister it. Any
> further attempts to remove after the first will throw a "not found" warning.
> 
> Call-stacks for reference:
> 
>    *drm_connector_unregister*+0x37/0x60 [drm]
>    drm_connector_unregister_all+0x30/0x60 [drm]
>    drm_modeset_unregister_all+0xe/0x30 [drm]
>    drm_dev_unregister+0x9c/0xb0 [drm]
>    i915_driver_unload+0x73/0x120 [i915]
> 
>    drm_dp_aux_unregister_devnode+0xf5/0x180 [drm_kms_helper]
>    *drm_dp_mst_topology_put_port*+0x4e/0xf0 [drm_kms_helper]
>    drm_dp_mst_topology_put_mstb+0x91/0x160 [drm_kms_helper]
>    drm_dp_mst_topology_mgr_set_mst+0x12b/0x2b0 [drm_kms_helper]
>    ? __finish_swait+0x10/0x40
>    drm_dp_mst_topology_mgr_destroy+0x11/0xa0 [drm_kms_helper]
>    intel_dp_encoder_flush_work+0x32/0xb0 [i915]
>    intel_ddi_encoder_destroy+0x32/0x60 [i915]
>    drm_mode_config_cleanup+0x51/0x2e0 [drm]
>    intel_modeset_cleanup+0xc8/0x140 [i915]
>    i915_driver_unload+0xa0/0x120 [i915]
> 
> A solution is to unregister the aux device immediately before the
> connector device is unregistered - if we are to keep the aux device as a
> child. Following current scheme with SST, it looks like
> drm_connector_funcs->early_unregister() is the right place to do so.
> To keep the balance, aux registration will then happen in
> drm_connector_funcs->late_register(). This will leave the SDP
> transaction handling part in DRM still, but pass the responsibility of
> creating and removing remote (fake) aux devices to the driver.
> 
> I have a WIP patch here for you to take a look. It should apply on top
> of the existing patchset:
> https://pastebin.com/1YJZhL4C
> 

This approach seems fine to me! I was thinking we might end up doing something
like this. My only thought is that we can probably write up a
drm_dp_mst_connector_late_register() and
drm_dp_mst_connector_early_unregister() that drivers can call from their
→late_register()/→early_unregister() callbacks that handles printing the debug
message, setting the parent and registering/unregistering the aux device. I'd
imagine someday in the future we'll probably have more things to add to those
callbacks for mst as well.

> I'd like to hear your thoughts, before I go and modify other drivers :)
> 
> Thanks,
> Leo
Leo Li June 27, 2019, 10:21 p.m. UTC | #7
Sorry for the late response! just jumping back on this now.

On 2019-05-16 5:40 p.m., Lyude Paul wrote:
> [CAUTION: External Email]
> 
> So a couple of things:
> 
> On Thu, 2019-05-16 at 11:17 -0400, sunpeng.li@amd.com wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> All available downstream ports - physical and logical - are exposed for
>> each MST device. They are listed in /dev/, following the same naming
>> scheme as SST devices by appending an incremental ID.
>>
>> Although all downstream ports are exposed, only some will work as
>> expected. Consider the following topology:
>>
>>                 +---------+
>>                 |  ASIC   |
>>                 +---------+
>>                Conn-0|
>>                      |
>>                 +----v----+
>>            +----| MST HUB |----+
>>            |    +---------+    |
>>            |                   |
>>            |Port-1       Port-2|
>>      +-----v-----+       +-----v-----+
>>      |  MST      |       |  SST      |
>>      |  Display  |       |  Display  |
>>      +-----------+       +-----------+
>>            |Port-1
>>            x
>>
>>   MST Path  | MST Device
>>   ----------+----------------------------------
>>   sst:0     | MST Hub
>>   mst:0-1   | MST Display
>>   mst:0-1-1 | MST Display's disconnected DP out
>>   mst:0-1-8 | MST Display's internal sink
>>   mst:0-2   | SST Display
>>
>> On certain MST displays, the upstream physical port will ACK DPCD reads.
>> However, reads on the local logical port to the internal sink will
>> *NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs.
>>
>> There may also be duplicates. Some displays will return the same GUID
>> when reading DPCD from both mst:0-1 and mst:0-1-8.
>>
>> There are some device-dependent behavior as well. The MST hub used
>> during testing will actually *ACK* read requests on a disconnected
>> physical port, whereas the MST displays will NAK.
>>
>> In light of these discrepancies, it's simpler to expose all downstream
>> ports - both physical and logical - and let the user decide what to use.
>>
>> Cc: Lyude Paul <lyude@redhat.com>
>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> Signed-off-by: Leo Li <sunpeng.li@amd.com>
>> ---
>>   drivers/gpu/drm/drm_dp_aux_dev.c      |  14 ++++-
>>   drivers/gpu/drm/drm_dp_mst_topology.c | 103 +++++++++++++++++++++++++++++
>> -----
>>   include/drm/drm_dp_helper.h           |   4 ++
>>   include/drm/drm_dp_mst_helper.h       |   6 ++
>>   4 files changed, 112 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c
>> b/drivers/gpu/drm/drm_dp_aux_dev.c
>> index 6d84611..01c02b9 100644
>> --- a/drivers/gpu/drm/drm_dp_aux_dev.c
>> +++ b/drivers/gpu/drm/drm_dp_aux_dev.c
>> @@ -34,6 +34,7 @@
>>   #include <linux/uaccess.h>
>>   #include <linux/uio.h>
>>   #include <drm/drm_dp_helper.h>
>> +#include <drm/drm_dp_mst_helper.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drmP.h>
>>
>> @@ -114,6 +115,7 @@ static ssize_t name_show(struct device *dev,
>>
>>        return res;
>>   }
>> +
>>   static DEVICE_ATTR_RO(name);
>>
>>   static struct attribute *drm_dp_aux_attrs[] = {
>> @@ -160,7 +162,11 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb,
>> struct iov_iter *to)
>>                        break;
>>                }
>>
>> -             res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
>> +             if (aux_dev->aux->is_remote)
>> +                     res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf,
>> todo);
>> +             else
>> +                     res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
>> +
> 
> It's still not at all clear to me why we're trying to avoid specifying actual
> callbacks for the aux device. We should remove this part entirely, remove the
> is_remote entry from struct drm_dp_aux, and then just specify our own hook in
> struct drm_dp_aux->transfer().
> 

I'm not sure if this would work well. The existing policy does retries
around the ->transfer() call. Using the same hook will cause a nested
retry - once when calling remote_aux->transfer, and another when calling
real_aux->transfer. The difference is the scope of the retry. The former
replays the entire aux transaction, while the latter replays just the
failed sideband packet. I think having the retry at the packet level
makes more sense. Either way, it shouldn't happen in a nested manner.

In general, we need a way to determine whether a message needs to be
sent via sideband. I'm not sure if there's a better way than setting a
'is_remote' flag?

Leo

>>                if (res <= 0)
>>                        break;
>>
>> @@ -207,7 +213,11 @@ static ssize_t auxdev_write_iter(struct kiocb *iocb,
>> struct iov_iter *from)
>>                        break;
>>                }
>>
>> -             res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
>> +             if (aux_dev->aux->is_remote)
>> +                     res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf,
>> todo);
>> +             else
>> +                     res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
>> +
>>                if (res <= 0)
>>                        break;
>>
>> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
>> b/drivers/gpu/drm/drm_dp_mst_topology.c
>> index 2ab16c9..54da68e 100644
>> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
>> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
>> @@ -35,6 +35,8 @@
>>   #include <drm/drm_atomic_helper.h>
>>   #include <drm/drm_crtc_helper.h>
>>
>> +#include "drm_crtc_helper_internal.h"
>> +
> 
> Unless I'm mistaken, this looks like some sort of ditritus.
> 
>>   /**
>>    * DOC: dp mst helper
>>    *
>> @@ -52,6 +54,9 @@ static int drm_dp_dpcd_write_payload(struct
>> drm_dp_mst_topology_mgr *mgr,
>>                                     int id,
>>                                     struct drm_dp_payload *payload);
>>
>> +static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
>> +                              struct drm_dp_mst_port *port,
>> +                              int offset, int size, u8 *bytes);
>>   static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
>>                                  struct drm_dp_mst_port *port,
>>                                  int offset, int size, u8 *bytes);
>> @@ -941,6 +946,8 @@ static void drm_dp_destroy_port(struct kref *kref)
>>        struct drm_dp_mst_topology_mgr *mgr = port->mgr;
>>
>>        if (!port->input) {
>> +             drm_dp_aux_unregister_devnode(&port->aux);
>> +
>>                port->vcpi.num_slots = 0;
>>
>>                kfree(port->cached_edid);
>> @@ -1095,6 +1102,46 @@ static bool drm_dp_port_setup_pdt(struct
>> drm_dp_mst_port *port)
>>        return send_link;
>>   }
>>
>> +/**
>> + * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via
>> sideband
>> + * @aux: Fake sideband AUX CH
>> + * @offset: address of the (first) register to read
>> + * @buffer: buffer to store the register values
>> + * @size: number of bytes in @buffer
>> + *
>> + * Performs the same functionality for remote devices via
>> + * sideband messaging as drm_dp_dpcd_read() does for local
>> + * devices via actual AUX CH.
>> + */
>> +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
>> +                          unsigned int offset, void *buffer, size_t size)
>> +{
>> +     struct drm_dp_mst_port *port = container_of(aux, struct
>> drm_dp_mst_port, aux);
>> +
>> +     return drm_dp_send_dpcd_read(port->mgr, port,
>> +                                  offset, size, buffer);
>> +}
>> +
>> +/**
>> + * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via
>> sideband
>> + * @aux: Fake sideband AUX CH
>> + * @offset: address of the (first) register to write
>> + * @buffer: buffer containing the values to write
>> + * @size: number of bytes in @buffer
>> + *
>> + * Performs the same functionality for remote devices via
>> + * sideband messaging as drm_dp_dpcd_write() does for local
>> + * devices via actual AUX CH.
>> + */
>> +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
>> +                           unsigned int offset, void *buffer, size_t size)
>> +{
>> +     struct drm_dp_mst_port *port = container_of(aux, struct
>> drm_dp_mst_port, aux);
>> +
>> +     return drm_dp_send_dpcd_write(port->mgr, port,
>> +                                   offset, size, buffer);
>> +}
>> +
>>   static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8
>> *guid)
>>   {
>>        int ret;
>> @@ -1158,6 +1205,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
>> *mstb,
>>                port->mgr = mstb->mgr;
>>                port->aux.name = "DPMST";
>>                port->aux.dev = dev->dev;
>> +             port->aux.is_remote = true;
>>                created = true;
>>        } else {
>>                old_pdt = port->pdt;
>> @@ -1188,7 +1236,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
>> *mstb,
>>                                drm_dp_send_enum_path_resources(mstb->mgr,
>> mstb, port);
>>                } else {
>>                        port->available_pbn = 0;
>> -                     }
>> +             }
>>        }
>>
>>        if (old_pdt != port->pdt && !port->input) {
>> @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct drm_dp_mst_branch
>> *mstb,
>>                        drm_connector_set_tile_property(port->connector);
>>                }
>>                (*mstb->mgr->cbs->register_connector)(port->connector);
> 
> This is wrong: we always want to setup everything in the connector first
> before trying to register it, not after. Otherwise, things explode like so:
> 
> [   13.305329] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
> [   13.305361] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
> [   13.305384] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
> [   13.305405] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
> [   13.305429] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
> [   13.305449] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
> [   13.305471] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> [   13.305490] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
> [   13.305512] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> [   13.305532] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> [   13.305552] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
> [   13.305571] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
> [   13.305592] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> [   13.305612] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
> [   13.305631] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> [   13.305651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> [   13.305725] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 0, ret: 0
> [   13.305768] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 1, ret: 0
> [   13.306088] [drm:drm_handle_vblank [drm]] vblank event on 325, current 325
> [   13.322514] [drm:drm_handle_vblank [drm]] vblank event on 313, current 313
> [   13.322612] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> [   13.322634] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
> [   13.322656] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> [   13.322676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
> [   13.322697] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
> [   13.322718] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
> [   13.322740] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
> [   13.322764] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 0
> [   13.322784] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
> [   13.339191] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 1
> [  451.149789] Console: switching to colour dummy device 80x25
> [  451.194596] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-A] unregistering
> [  451.194666] [drm:drm_sysfs_connector_remove [drm]] removing "eDP-1" from sysfs
> [  451.194718] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-B] unregistering
> [  451.194766] [drm:drm_sysfs_connector_remove [drm]] removing "DP-1" from sysfs
> [  451.194791] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-1" from sysfs
> [  451.194835] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPDDC-C] unregistering
> [  451.194880] [drm:drm_sysfs_connector_remove [drm]] removing "DP-2" from sysfs
> [  451.194903] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-2" from sysfs
> [  451.194924] [drm:drm_sysfs_connector_remove [drm]] removing "DP-3" from sysfs
> [  451.194950] [drm:drm_sysfs_connector_remove [drm]] removing "DP-4" from sysfs
> [  451.194975] [drm:drm_sysfs_connector_remove [drm]] removing "DP-5" from sysfs
> [  451.204535] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
> [  451.204551] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
> [  451.204566] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
> [  451.204582] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> [  451.204596] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
> [  451.204611] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
> [  451.204621] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
> [  451.204631] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
> [  451.204641] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> [  451.204651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
> [  451.204662] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> [  451.204671] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> [  451.204680] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
> [  451.204689] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
> [  451.204699] [drm:drm_dp_mst_duplicate_state [drm_kms_helper]] port 00000000dde1b00a (5)
> [  451.204703] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (4)
> [  451.411817] [drm:intel_panel_actually_set_backlight [i915]] set backlight PWM = 0
> [  451.420911] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-A: 0x00600 AUX <- (ret=  1) 02
> [  451.425358] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x11101010, pins 0x00000010, long 0x00000000
> [  451.425422] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - short
> [  451.471777] [drm:drm_dp_mst_topology_get_mstb_validated [drm_kms_helper]] mstb 00000000eec1a629 (2)
> [  451.473361] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
> [  451.473465] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - long
> [  452.207301] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
> [  452.207395] [drm:intel_hpd_irq_handler [i915]] digital hpd port A - long
> [  452.340311] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00000 AUX -> (ret= 15) 11 0a 02 41 00 00 01 00 02 00 00 00 00 0b 00
> [  452.341060] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00201 AUX -> (ret=  1) 00
> [  452.341584] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000 AUX <- (ret= 10) 10 47 d3 11 11 01 00 00 00 f4
> [  452.343183] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
> [  452.343286] [drm:intel_hpd_irq_handler [i915]] digital hpd port B - short
> [  452.344765] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
> [  452.346263] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400 AUX -> (ret= 16) 10 46 d6 11 10 01 00 00 78 00 00 00 00 00 00 00
> [  452.346287] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb 00000000eec1a629 (3)
> [  452.346305] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (2)
> [  452.346405] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (1)
> [  452.347529] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003 AUX <- (ret=  3) 10 00 00
> [  452.348672] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x002c0 AUX <- (ret=  1) 01
> [  452.350168] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 77 77 01 00
> [  452.351328] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x001c0 AUX <- (ret=  3) 01 01 00
> [  452.352665] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
> [  452.358905] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
> [  452.360327] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 01
> [  452.361660] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0 AUX -> (ret=  1) 03
> [  452.361681] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (3)
> [  452.361700] [drm:drm_dp_mst_topology_get_port_validated [drm_kms_helper]] port 00000000dde1b00a (2)
> [  452.362894] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000 AUX <- (ret=  6) 10 43 c7 25 10 c0
> [  452.364318] [drm:gen8_de_irq_handler [i915]] hotplug event received, stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
> [  452.364421] [drm:intel_hpd_irq_handler [i915]] digital hpd port B - short
> [  452.365929] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
> [  452.367361] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400 AUX -> (ret= 16) 10 43 c7 25 10 c0 00 00 00 00 00 00 00 00 00 00
> [  452.367388] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb 00000000eec1a629 (2)
> [  452.367407] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (1)
> [  452.367460] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000dde1b00a (1)
> [  452.368548] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003 AUX <- (ret=  3) 10 00 00
> [  452.368803] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00600 AUX <- (ret=  1) 02
> [  452.368970] [drm:intel_dump_cdclk_state [i915]] Changing CDCLK to 337500 kHz, VCO 8100000 kHz, ref 24000 kHz, bypass 24000 kHz, voltage level 0
> [  452.369269] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (1)
> [  452.369330] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (1)
> [  452.369422] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
> [  452.369466] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (4)
> [  452.369515] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
> [  452.369558] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (4)
> [  452.369608] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (3)
> [  452.369660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (2)
> [  452.369690] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (2)
> [  452.369750] [drm:drm_irq_uninstall [drm]] irq=177
> [  452.406452] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002 AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 00 00 80 00
> [  452.412626] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (3)
> [  452.412636] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 91 (2)
> [  452.412644] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 98 (2)
> [  452.412652] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 104 (2)
> [  452.412660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 109 (2)
> [  452.412668] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (3)
> [  452.412676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (2)
> [  452.412684] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (2)
> [  452.412692] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (2)
> [  452.412700] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (2)
> [  452.412708] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (1)
> [  452.424450] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00111 AUX <- (ret=  1) 00
> [  452.424454] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb 00000000eec1a629 (0)
> [  452.424457] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000eeef3cfd (0)
> [  452.424461] ------------[ cut here ]------------
> [  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
> [  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
> [  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G           O      5.1.0Lyude-Test+ #1
> [  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
> [  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
> [  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> [  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> [  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
> [  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
> [  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09: 0000000000000046
> [  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd5f77010
> [  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15: dead000000000100
> [  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
> [  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
> [  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [  452.424512] Call Trace:
> [  452.424516]  device_del+0x75/0x360
> [  452.424518]  ? class_find_device+0x96/0xf0
> [  452.424520]  device_unregister+0x16/0x60
> [  452.424521]  device_destroy+0x3a/0x40
> [  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> [  452.424534]  ? drm_dbg+0x87/0x90 [drm]
> [  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> [  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> [  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
> [  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> [  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> [  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> [  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> [  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
> [  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
> [  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
> [  452.424647]  pci_device_remove+0x3b/0xc0
> [  452.424649]  device_release_driver_internal+0xe4/0x1d0
> [  452.424651]  pci_stop_bus_device+0x69/0x90
> [  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> [  452.424655]  remove_store+0x75/0x90
> [  452.424656]  kernfs_fop_write+0x116/0x190
> [  452.424658]  vfs_write+0xa5/0x1a0
> [  452.424660]  ksys_write+0x57/0xd0
> [  452.424663]  do_syscall_64+0x55/0x150
> [  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [  452.424667] RIP: 0033:0x7f8cc1e7d038
> [  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> [  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
> [  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
> [  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
> [  452.424675] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
> [  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
> [  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424680] ---[ end trace a1c11eaf054910a3 ]---
> [  452.424751] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
> [  452.424755] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 000000000f6aa5a3 (0)
> [  452.424765] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (1)
> [  452.424770] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000eeef3cfd (1)
> [  452.424773] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000eeef3cfd (0)
> [  452.424776] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (4)
> [  452.424783] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug event
> [  452.424790] ------------[ cut here ]------------
> [  452.424791] sysfs group 'power' not found for kobject 'drm_dp_aux4'
> [  452.424795] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424796] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
> [  452.424809] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G        W  O      5.1.0Lyude-Test+ #1
> [  452.424811] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
> [  452.424812] RIP: 0010:sysfs_remove_group+0x76/0x80
> [  452.424813] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> [  452.424815] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> [  452.424816] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
> [  452.424817] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
> [  452.424818] RBP: ffffffffa9ea12e0 R08: 00000000000007d1 R09: 0000000000000046
> [  452.424820] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd50d0410
> [  452.424821] R13: ffff981fd6ebbebc R14: dead000000000200 R15: dead000000000100
> [  452.424822] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
> [  452.424823] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  452.424824] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
> [  452.424825] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  452.424826] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [  452.424827] Call Trace:
> [  452.424829]  device_del+0x75/0x360
> [  452.424830]  ? class_find_device+0x96/0xf0
> [  452.424832]  device_unregister+0x16/0x60
> [  452.424833]  device_destroy+0x3a/0x40
> [  452.424837]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> [  452.424841]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> [  452.424845]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> [  452.424849]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
> [  452.424854]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> [  452.424873]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> [  452.424892]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> [  452.424900]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> [  452.424920]  intel_modeset_cleanup+0xc8/0x140 [i915]
> [  452.424932]  i915_driver_unload+0xa8/0x130 [i915]
> [  452.424943]  i915_pci_remove+0x1e/0x40 [i915]
> [  452.424945]  pci_device_remove+0x3b/0xc0
> [  452.424947]  device_release_driver_internal+0xe4/0x1d0
> [  452.424948]  pci_stop_bus_device+0x69/0x90
> [  452.424950]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> [  452.424951]  remove_store+0x75/0x90
> [  452.424953]  kernfs_fop_write+0x116/0x190
> [  452.424954]  vfs_write+0xa5/0x1a0
> [  452.424956]  ksys_write+0x57/0xd0
> [  452.424957]  do_syscall_64+0x55/0x150
> [  452.424959]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [  452.424960] RIP: 0033:0x7f8cc1e7d038
> [  452.424961] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> [  452.424963] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [  452.424965] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
> [  452.424966] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
> [  452.424967] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
> [  452.424968] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
> [  452.424969] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
> [  452.424971] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.424972] ---[ end trace a1c11eaf054910a4 ]---
> [  452.424992] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
> [  452.424997] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 00000000dde1b00a (0)
> [  452.425006] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (1)
> [  452.425010] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000000f6aa5a3 (1)
> [  452.425014] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000000f6aa5a3 (0)
> [  452.425017] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (3)
> [  452.425023] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug event
> [  452.425028] ------------[ cut here ]------------
> [  452.425029] sysfs group 'power' not found for kobject 'drm_dp_aux3'
> [  452.425033] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.425034] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801 intel_xhci_usb_role_switch processor_thermal_device typec_ucsi intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage i2c_dev
> [  452.425047] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted: G        W  O      5.1.0Lyude-Test+ #1
> [  452.425048] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018
> [  452.425050] RIP: 0010:sysfs_remove_group+0x76/0x80
> [  452.425051] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> [  452.425053] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> [  452.425054] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000006
> [  452.425055] RDX: 0000000000000007 RSI: 0000000000000086 RDI: ffff981fde2d5a00
> [  452.425056] RBP: ffffffffa9ea12e0 R08: 000000000000080f R09: 0000000000000046
> [  452.425057] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12: ffff981fd50d1810
> [  452.425058] R13: ffff981fd6ebbe1c R14: dead000000000200 R15: dead000000000100
> [  452.425059] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000) knlGS:0000000000000000
> [  452.425061] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  452.425062] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4: 00000000003606e0
> [  452.425063] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  452.425064] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [  452.425065] Call Trace:
> [  452.425066]  device_del+0x75/0x360
> [  452.425068]  ? class_find_device+0x96/0xf0
> [  452.425069]  device_unregister+0x16/0x60
> [  452.425070]  device_destroy+0x3a/0x40
> [  452.425074]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> [  452.425078]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> [  452.425083]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> [  452.425087]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0 [drm_kms_helper]
> [  452.425091]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> [  452.425110]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> [  452.425128]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> [  452.425137]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> [  452.425157]  intel_modeset_cleanup+0xc8/0x140 [i915]
> [  452.425168]  i915_driver_unload+0xa8/0x130 [i915]
> [  452.425180]  i915_pci_remove+0x1e/0x40 [i915]
> [  452.425182]  pci_device_remove+0x3b/0xc0
> [  452.425183]  device_release_driver_internal+0xe4/0x1d0
> [  452.425185]  pci_stop_bus_device+0x69/0x90
> [  452.425186]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> [  452.425188]  remove_store+0x75/0x90
> [  452.425189]  kernfs_fop_write+0x116/0x190
> [  452.425191]  vfs_write+0xa5/0x1a0
> [  452.425192]  ksys_write+0x57/0xd0
> [  452.425194]  do_syscall_64+0x55/0x150
> [  452.425195]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [  452.425197] RIP: 0033:0x7f8cc1e7d038
> [  452.425198] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> [  452.425199] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [  452.425201] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f8cc1e7d038
> [  452.425202] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI: 0000000000000001
> [  452.425203] RBP: 000056515aefbf00 R08: 000000000000000a R09: 00007f8cc1f0ee80
> [  452.425204] R10: 000000000000000a R11: 0000000000000246 R12: 00007f8cc1f50780
> [  452.425205] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15: 0000000000000002
> [  452.425207] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256 sysfs_remove_group+0x76/0x80
> [  452.425208] ---[ end trace a1c11eaf054910a5 ]---
> [  452.425282] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]] drm_dp_aux_dev: aux [DPMST] unregistering
> [  452.425288] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port 000000002ba3174e (0)
> [  452.425292] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 000000002ba3174e (0)
> [  452.425295] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (2)
> [  452.425299] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (1)
> [  452.425311] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (1)
> [  452.425318] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (1)
> [  452.425365] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port 00000000dde1b00a (0)
> [  452.425368] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb 00000000eec1a629 (0)
> 
> So, we need to move the drm_dp_aux_register_devnode() call above the connector
> registration callback. Same goes for the port->aux.dev = port->connector-
>> kdev; assignment that you do in patch 3/7 (and of course, you can remove the
> connector registration status check there now).
> 
>> +
>> +             drm_dp_aux_register_devnode(&port->aux);
>>        }
>>
>>   out:
>> @@ -1404,7 +1454,6 @@ static bool drm_dp_validate_guid(struct
>> drm_dp_mst_topology_mgr *mgr,
>>        return false;
>>   }
>>
>> -#if 0
>>   static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num,
>> u32 offset, u8 num_bytes)
>>   {
>>        struct drm_dp_sideband_msg_req_body req;
>> @@ -1417,7 +1466,6 @@ static int build_dpcd_read(struct
>> drm_dp_sideband_msg_tx *msg, u8 port_num, u32
>>
>>        return 0;
>>   }
>> -#endif
>>
>>   static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr,
>>                                    bool up, u8 *msg, int len)
>> @@ -1994,26 +2042,55 @@ int drm_dp_update_payload_part2(struct
>> drm_dp_mst_topology_mgr *mgr)
>>   }
>>   EXPORT_SYMBOL(drm_dp_update_payload_part2);
>>
>> -#if 0 /* unused as of yet */
>>   static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
>>                                 struct drm_dp_mst_port *port,
>> -                              int offset, int size)
>> +                              int offset, int size, u8 *bytes)
>>   {
>>        int len;
>> +     int ret = 0;
>>        struct drm_dp_sideband_msg_tx *txmsg;
>> +     struct drm_dp_mst_branch *mstb;
>> +
>> +     mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
>> +     if (!mstb)
>> +             return -EINVAL;
>>
>>        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
>> -     if (!txmsg)
>> -             return -ENOMEM;
>> +     if (!txmsg) {
>> +             ret = -ENOMEM;
>> +             goto fail_put;
>> +     }
>>
>> -     len = build_dpcd_read(txmsg, port->port_num, 0, 8);
>> +     len = build_dpcd_read(txmsg, port->port_num, offset, size);
>>        txmsg->dst = port->parent;
>>
>>        drm_dp_queue_down_tx(mgr, txmsg);
>>
>> -     return 0;
>> +     ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
>> +     if (ret < 0)
>> +             goto fail_free;
>> +
>> +     /* DPCD read should never be NACKed */
>> +     if (WARN_ON_ONCE(txmsg->reply.reply_type == 1)) {
>> +             ret = -EIO;
>> +             goto fail_free;
>> +     }
>> +
>> +     if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) {
>> +             ret = -EPROTO;
>> +             goto fail_free;
>> +     }
>> +
>> +     ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes,
>> size);
>> +     memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret);
>> +
>> +fail_free:
>> +     kfree(txmsg);
>> +fail_put:
>> +     drm_dp_put_mst_branch_device(mstb);
>> +
>> +     return ret;
>>   }
>> -#endif
>>
>>   static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
>>                                  struct drm_dp_mst_port *port,
>> @@ -2041,9 +2118,9 @@ static int drm_dp_send_dpcd_write(struct
>> drm_dp_mst_topology_mgr *mgr,
>>
>>        ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
>>        if (ret > 0) {
>> -             if (txmsg->reply.reply_type == 1) {
>> -                     ret = -EINVAL;
>> -             } else
>> +             if (txmsg->reply.reply_type == 1)
>> +                     ret = -EIO;
>> +             else
>>                        ret = 0;
>>        }
>>        kfree(txmsg);
>> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
>> index 509667e..6dea76a 100644
>> --- a/include/drm/drm_dp_helper.h
>> +++ b/include/drm/drm_dp_helper.h
>> @@ -1265,6 +1265,10 @@ struct drm_dp_aux {
>>         * @cec: struct containing fields used for CEC-Tunneling-over-AUX.
>>         */
>>        struct drm_dp_aux_cec cec;
>> +     /**
>> +      * @is_remote: Is this "AUX CH" actually using sideband messaging.
>> +      */
>> +     bool is_remote;
>>   };
>>
>>   ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
>> diff --git a/include/drm/drm_dp_mst_helper.h
>> b/include/drm/drm_dp_mst_helper.h
>> index 371cc28..30f8c11 100644
>> --- a/include/drm/drm_dp_mst_helper.h
>> +++ b/include/drm/drm_dp_mst_helper.h
>> @@ -615,6 +615,12 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
>>
>>   void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr);
>>   int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
>> +
>> +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
>> +                          unsigned int offset, void *buffer, size_t size);
>> +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
>> +                           unsigned int offset, void *buffer, size_t size);
>> +
>>   struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct
>> drm_atomic_state *state,
>>                                                                    struct
>> drm_dp_mst_topology_mgr *mgr);
>>   int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
> --
> Cheers,
>          Lyude Paul
>
Lyude Paul July 1, 2019, 8:43 p.m. UTC | #8
On Thu, 2019-06-27 at 22:21 +0000, Li, Sun peng (Leo) wrote:
> Sorry for the late response! just jumping back on this now.
> 
> On 2019-05-16 5:40 p.m., Lyude Paul wrote:
> > [CAUTION: External Email]
> > 
> > So a couple of things:
> > 
> > On Thu, 2019-05-16 at 11:17 -0400, sunpeng.li@amd.com wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > All available downstream ports - physical and logical - are exposed for
> > > each MST device. They are listed in /dev/, following the same naming
> > > scheme as SST devices by appending an incremental ID.
> > > 
> > > Although all downstream ports are exposed, only some will work as
> > > expected. Consider the following topology:
> > > 
> > >                 +---------+
> > >                 |  ASIC   |
> > >                 +---------+
> > >                Conn-0|
> > >                      |
> > >                 +----v----+
> > >            +----| MST HUB |----+
> > >            |    +---------+    |
> > >            |                   |
> > >            |Port-1       Port-2|
> > >      +-----v-----+       +-----v-----+
> > >      |  MST      |       |  SST      |
> > >      |  Display  |       |  Display  |
> > >      +-----------+       +-----------+
> > >            |Port-1
> > >            x
> > > 
> > >   MST Path  | MST Device
> > >   ----------+----------------------------------
> > >   sst:0     | MST Hub
> > >   mst:0-1   | MST Display
> > >   mst:0-1-1 | MST Display's disconnected DP out
> > >   mst:0-1-8 | MST Display's internal sink
> > >   mst:0-2   | SST Display
> > > 
> > > On certain MST displays, the upstream physical port will ACK DPCD reads.
> > > However, reads on the local logical port to the internal sink will
> > > *NAK*. i.e. reading mst:0-1 ACKs, but mst:0-1-8 NAKs.
> > > 
> > > There may also be duplicates. Some displays will return the same GUID
> > > when reading DPCD from both mst:0-1 and mst:0-1-8.
> > > 
> > > There are some device-dependent behavior as well. The MST hub used
> > > during testing will actually *ACK* read requests on a disconnected
> > > physical port, whereas the MST displays will NAK.
> > > 
> > > In light of these discrepancies, it's simpler to expose all downstream
> > > ports - both physical and logical - and let the user decide what to use.
> > > 
> > > Cc: Lyude Paul <lyude@redhat.com>
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > Signed-off-by: Leo Li <sunpeng.li@amd.com>
> > > ---
> > >   drivers/gpu/drm/drm_dp_aux_dev.c      |  14 ++++-
> > >   drivers/gpu/drm/drm_dp_mst_topology.c | 103
> > > +++++++++++++++++++++++++++++
> > > -----
> > >   include/drm/drm_dp_helper.h           |   4 ++
> > >   include/drm/drm_dp_mst_helper.h       |   6 ++
> > >   4 files changed, 112 insertions(+), 15 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c
> > > b/drivers/gpu/drm/drm_dp_aux_dev.c
> > > index 6d84611..01c02b9 100644
> > > --- a/drivers/gpu/drm/drm_dp_aux_dev.c
> > > +++ b/drivers/gpu/drm/drm_dp_aux_dev.c
> > > @@ -34,6 +34,7 @@
> > >   #include <linux/uaccess.h>
> > >   #include <linux/uio.h>
> > >   #include <drm/drm_dp_helper.h>
> > > +#include <drm/drm_dp_mst_helper.h>
> > >   #include <drm/drm_crtc.h>
> > >   #include <drm/drmP.h>
> > > 
> > > @@ -114,6 +115,7 @@ static ssize_t name_show(struct device *dev,
> > > 
> > >        return res;
> > >   }
> > > +
> > >   static DEVICE_ATTR_RO(name);
> > > 
> > >   static struct attribute *drm_dp_aux_attrs[] = {
> > > @@ -160,7 +162,11 @@ static ssize_t auxdev_read_iter(struct kiocb *iocb,
> > > struct iov_iter *to)
> > >                        break;
> > >                }
> > > 
> > > -             res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
> > > +             if (aux_dev->aux->is_remote)
> > > +                     res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf,
> > > todo);
> > > +             else
> > > +                     res = drm_dp_dpcd_read(aux_dev->aux, pos, buf,
> > > todo);
> > > +
> > 
> > It's still not at all clear to me why we're trying to avoid specifying
> > actual
> > callbacks for the aux device. We should remove this part entirely, remove
> > the
> > is_remote entry from struct drm_dp_aux, and then just specify our own hook
> > in
> > struct drm_dp_aux->transfer().
> > 
> 
> I'm not sure if this would work well. The existing policy does retries
> around the ->transfer() call. Using the same hook will cause a nested
> retry - once when calling remote_aux->transfer, and another when calling
> real_aux->transfer. The difference is the scope of the retry. The former
> replays the entire aux transaction, while the latter replays just the
> failed sideband packet. I think having the retry at the packet level
> makes more sense. Either way, it shouldn't happen in a nested manner.
> 
> In general, we need a way to determine whether a message needs to be
> sent via sideband. I'm not sure if there's a better way than setting a
> 'is_remote' flag?

oh-this is a very good point actually! I suppose we would certainly want to be
able to retry on a packet level instead. Since that's the case, I think going
with the current is_remote solution should be fine then. Might be worth noting
the reasoning behind this with a comment

> 
> Leo
> 
> > >                if (res <= 0)
> > >                        break;
> > > 
> > > @@ -207,7 +213,11 @@ static ssize_t auxdev_write_iter(struct kiocb
> > > *iocb,
> > > struct iov_iter *from)
> > >                        break;
> > >                }
> > > 
> > > -             res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
> > > +             if (aux_dev->aux->is_remote)
> > > +                     res = drm_dp_mst_dpcd_write(aux_dev->aux, pos,
> > > buf,
> > > todo);
> > > +             else
> > > +                     res = drm_dp_dpcd_write(aux_dev->aux, pos, buf,
> > > todo);
> > > +
> > >                if (res <= 0)
> > >                        break;
> > > 
> > > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> > > b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > index 2ab16c9..54da68e 100644
> > > --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> > > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > @@ -35,6 +35,8 @@
> > >   #include <drm/drm_atomic_helper.h>
> > >   #include <drm/drm_crtc_helper.h>
> > > 
> > > +#include "drm_crtc_helper_internal.h"
> > > +
> > 
> > Unless I'm mistaken, this looks like some sort of ditritus.
> > 
> > >   /**
> > >    * DOC: dp mst helper
> > >    *
> > > @@ -52,6 +54,9 @@ static int drm_dp_dpcd_write_payload(struct
> > > drm_dp_mst_topology_mgr *mgr,
> > >                                     int id,
> > >                                     struct drm_dp_payload *payload);
> > > 
> > > +static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
> > > +                              struct drm_dp_mst_port *port,
> > > +                              int offset, int size, u8 *bytes);
> > >   static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
> > >                                  struct drm_dp_mst_port *port,
> > >                                  int offset, int size, u8 *bytes);
> > > @@ -941,6 +946,8 @@ static void drm_dp_destroy_port(struct kref *kref)
> > >        struct drm_dp_mst_topology_mgr *mgr = port->mgr;
> > > 
> > >        if (!port->input) {
> > > +             drm_dp_aux_unregister_devnode(&port->aux);
> > > +
> > >                port->vcpi.num_slots = 0;
> > > 
> > >                kfree(port->cached_edid);
> > > @@ -1095,6 +1102,46 @@ static bool drm_dp_port_setup_pdt(struct
> > > drm_dp_mst_port *port)
> > >        return send_link;
> > >   }
> > > 
> > > +/**
> > > + * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via
> > > sideband
> > > + * @aux: Fake sideband AUX CH
> > > + * @offset: address of the (first) register to read
> > > + * @buffer: buffer to store the register values
> > > + * @size: number of bytes in @buffer
> > > + *
> > > + * Performs the same functionality for remote devices via
> > > + * sideband messaging as drm_dp_dpcd_read() does for local
> > > + * devices via actual AUX CH.
> > > + */
> > > +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
> > > +                          unsigned int offset, void *buffer, size_t
> > > size)
> > > +{
> > > +     struct drm_dp_mst_port *port = container_of(aux, struct
> > > drm_dp_mst_port, aux);
> > > +
> > > +     return drm_dp_send_dpcd_read(port->mgr, port,
> > > +                                  offset, size, buffer);
> > > +}
> > > +
> > > +/**
> > > + * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via
> > > sideband
> > > + * @aux: Fake sideband AUX CH
> > > + * @offset: address of the (first) register to write
> > > + * @buffer: buffer containing the values to write
> > > + * @size: number of bytes in @buffer
> > > + *
> > > + * Performs the same functionality for remote devices via
> > > + * sideband messaging as drm_dp_dpcd_write() does for local
> > > + * devices via actual AUX CH.
> > > + */
> > > +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
> > > +                           unsigned int offset, void *buffer, size_t
> > > size)
> > > +{
> > > +     struct drm_dp_mst_port *port = container_of(aux, struct
> > > drm_dp_mst_port, aux);
> > > +
> > > +     return drm_dp_send_dpcd_write(port->mgr, port,
> > > +                                   offset, size, buffer);
> > > +}
> > > +
> > >   static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8
> > > *guid)
> > >   {
> > >        int ret;
> > > @@ -1158,6 +1205,7 @@ static void drm_dp_add_port(struct
> > > drm_dp_mst_branch
> > > *mstb,
> > >                port->mgr = mstb->mgr;
> > >                port->aux.name = "DPMST";
> > >                port->aux.dev = dev->dev;
> > > +             port->aux.is_remote = true;
> > >                created = true;
> > >        } else {
> > >                old_pdt = port->pdt;
> > > @@ -1188,7 +1236,7 @@ static void drm_dp_add_port(struct
> > > drm_dp_mst_branch
> > > *mstb,
> > >                                drm_dp_send_enum_path_resources(mstb-
> > > >mgr,
> > > mstb, port);
> > >                } else {
> > >                        port->available_pbn = 0;
> > > -                     }
> > > +             }
> > >        }
> > > 
> > >        if (old_pdt != port->pdt && !port->input) {
> > > @@ -1220,6 +1268,8 @@ static void drm_dp_add_port(struct
> > > drm_dp_mst_branch
> > > *mstb,
> > >                        drm_connector_set_tile_property(port->connector);
> > >                }
> > >                (*mstb->mgr->cbs->register_connector)(port->connector);
> > 
> > This is wrong: we always want to setup everything in the connector first
> > before trying to register it, not after. Otherwise, things explode like
> > so:
> > 
> > [   13.305329] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
> > [   13.305361] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
> > [   13.305384] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
> > [   13.305405] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
> > [   13.305429] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
> > [   13.305449] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
> > [   13.305471] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> > [   13.305490] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
> > [   13.305512] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> > [   13.305532] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> > [   13.305552] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (5)
> > [   13.305571] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (6)
> > [   13.305592] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> > [   13.305612] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
> > [   13.305631] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> > [   13.305651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> > [   13.305725] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 0,
> > ret: 0
> > [   13.305768] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 1,
> > ret: 0
> > [   13.306088] [drm:drm_handle_vblank [drm]] vblank event on 325, current
> > 325
> > [   13.322514] [drm:drm_handle_vblank [drm]] vblank event on 313, current
> > 313
> > [   13.322612] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> > [   13.322634] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
> > [   13.322656] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> > [   13.322676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
> > [   13.322697] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
> > [   13.322718] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
> > [   13.322740] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
> > [   13.322764] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 0
> > [   13.322784] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
> > [   13.339191] [drm:vblank_disable_fn [drm]] disabling vblank on crtc 1
> > [  451.149789] Console: switching to colour dummy device 80x25
> > [  451.194596] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPDDC-A] unregistering
> > [  451.194666] [drm:drm_sysfs_connector_remove [drm]] removing "eDP-1"
> > from sysfs
> > [  451.194718] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPDDC-B] unregistering
> > [  451.194766] [drm:drm_sysfs_connector_remove [drm]] removing "DP-1" from
> > sysfs
> > [  451.194791] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-1"
> > from sysfs
> > [  451.194835] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPDDC-C] unregistering
> > [  451.194880] [drm:drm_sysfs_connector_remove [drm]] removing "DP-2" from
> > sysfs
> > [  451.194903] [drm:drm_sysfs_connector_remove [drm]] removing "HDMI-A-2"
> > from sysfs
> > [  451.194924] [drm:drm_sysfs_connector_remove [drm]] removing "DP-3" from
> > sysfs
> > [  451.194950] [drm:drm_sysfs_connector_remove [drm]] removing "DP-4" from
> > sysfs
> > [  451.194975] [drm:drm_sysfs_connector_remove [drm]] removing "DP-5" from
> > sysfs
> > [  451.204535] [drm:drm_mode_object_get [drm]] OBJ ID: 123 (1)
> > [  451.204551] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (2)
> > [  451.204566] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (3)
> > [  451.204582] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (5)
> > [  451.204596] [drm:drm_mode_object_get [drm]] OBJ ID: 85 (6)
> > [  451.204611] [drm:drm_mode_object_get [drm]] OBJ ID: 124 (1)
> > [  451.204621] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (2)
> > [  451.204631] [drm:drm_mode_object_get [drm]] OBJ ID: 113 (4)
> > [  451.204641] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (5)
> > [  451.204651] [drm:drm_mode_object_get [drm]] OBJ ID: 86 (6)
> > [  451.204662] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (6)
> > [  451.204671] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (6)
> > [  451.204680] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (5)
> > [  451.204689] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (4)
> > [  451.204699] [drm:drm_dp_mst_duplicate_state [drm_kms_helper]] port
> > 00000000dde1b00a (5)
> > [  451.204703] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000dde1b00a (4)
> > [  451.411817] [drm:intel_panel_actually_set_backlight [i915]] set
> > backlight PWM = 0
> > [  451.420911] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-A: 0x00600
> > AUX <- (ret=  1) 02
> > [  451.425358] [drm:gen8_de_irq_handler [i915]] hotplug event received,
> > stat 0x01000000, dig 0x11101010, pins 0x00000010, long 0x00000000
> > [  451.425422] [drm:intel_hpd_irq_handler [i915]] digital hpd port A -
> > short
> > [  451.471777] [drm:drm_dp_mst_topology_get_mstb_validated
> > [drm_kms_helper]] mstb 00000000eec1a629 (2)
> > [  451.473361] [drm:gen8_de_irq_handler [i915]] hotplug event received,
> > stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
> > [  451.473465] [drm:intel_hpd_irq_handler [i915]] digital hpd port A -
> > long
> > [  452.207301] [drm:gen8_de_irq_handler [i915]] hotplug event received,
> > stat 0x01000000, dig 0x12101010, pins 0x00000010, long 0x00000010
> > [  452.207395] [drm:intel_hpd_irq_handler [i915]] digital hpd port A -
> > long
> > [  452.340311] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00000
> > AUX -> (ret= 15) 11 0a 02 41 00 00 01 00 02 00 00 00 00 0b 00
> > [  452.341060] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-A: 0x00201
> > AUX -> (ret=  1) 00
> > [  452.341584] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000
> > AUX <- (ret= 10) 10 47 d3 11 11 01 00 00 00 f4
> > [  452.343183] [drm:gen8_de_irq_handler [i915]] hotplug event received,
> > stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
> > [  452.343286] [drm:intel_hpd_irq_handler [i915]] digital hpd port B -
> > short
> > [  452.344765] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002
> > AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
> > [  452.346263] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400
> > AUX -> (ret= 16) 10 46 d6 11 10 01 00 00 78 00 00 00 00 00 00 00
> > [  452.346287] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb
> > 00000000eec1a629 (3)
> > [  452.346305] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb
> > 00000000eec1a629 (2)
> > [  452.346405] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb
> > 00000000eec1a629 (1)
> > [  452.347529] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003
> > AUX <- (ret=  3) 10 00 00
> > [  452.348672] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x002c0
> > AUX <- (ret=  1) 01
> > [  452.350168] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002
> > AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 77 77 01 00
> > [  452.351328] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x001c0
> > AUX <- (ret=  3) 01 01 00
> > [  452.352665] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0
> > AUX -> (ret=  1) 01
> > [  452.358905] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0
> > AUX -> (ret=  1) 01
> > [  452.360327] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0
> > AUX -> (ret=  1) 01
> > [  452.361660] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x002c0
> > AUX -> (ret=  1) 03
> > [  452.361681] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000dde1b00a (3)
> > [  452.361700] [drm:drm_dp_mst_topology_get_port_validated
> > [drm_kms_helper]] port 00000000dde1b00a (2)
> > [  452.362894] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x01000
> > AUX <- (ret=  6) 10 43 c7 25 10 c0
> > [  452.364318] [drm:gen8_de_irq_handler [i915]] hotplug event received,
> > stat 0x00200000, dig 0x10101011, pins 0x00000020, long 0x00000000
> > [  452.364421] [drm:intel_hpd_irq_handler [i915]] digital hpd port B -
> > short
> > [  452.365929] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002
> > AUX -> (ret= 14) 01 10 00 00 00 00 00 00 00 00 77 77 01 00
> > [  452.367361] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x01400
> > AUX -> (ret= 16) 10 43 c7 25 10 c0 00 00 00 00 00 00 00 00 00 00
> > [  452.367388] [drm:drm_dp_get_mst_branch_device [drm_kms_helper]] mstb
> > 00000000eec1a629 (2)
> > [  452.367407] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb
> > 00000000eec1a629 (1)
> > [  452.367460] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port
> > 00000000dde1b00a (1)
> > [  452.368548] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x02003
> > AUX <- (ret=  3) 10 00 00
> > [  452.368803] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00600
> > AUX <- (ret=  1) 02
> > [  452.368970] [drm:intel_dump_cdclk_state [i915]] Changing CDCLK to
> > 337500 kHz, VCO 8100000 kHz, ref 24000 kHz, bypass 24000 kHz, voltage
> > level 0
> > [  452.369269] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 123 (1)
> > [  452.369330] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 124 (1)
> > [  452.369422] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (5)
> > [  452.369466] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (4)
> > [  452.369515] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (5)
> > [  452.369558] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (4)
> > [  452.369608] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (3)
> > [  452.369660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (2)
> > [  452.369690] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000dde1b00a (2)
> > [  452.369750] [drm:drm_irq_uninstall [drm]] irq=177
> > [  452.406452] [drm:drm_dp_dpcd_read [drm_kms_helper]] DPDDC-B: 0x02002
> > AUX -> (ret= 14) 01 00 00 00 00 00 00 00 00 00 00 00 80 00
> > [  452.412626] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (3)
> > [  452.412636] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 91 (2)
> > [  452.412644] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 98 (2)
> > [  452.412652] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 104 (2)
> > [  452.412660] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 109 (2)
> > [  452.412668] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (3)
> > [  452.412676] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (2)
> > [  452.412684] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (2)
> > [  452.412692] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 85 (2)
> > [  452.412700] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (2)
> > [  452.412708] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 113 (1)
> > [  452.424450] [drm:drm_dp_dpcd_write [drm_kms_helper]] DPDDC-B: 0x00111
> > AUX <- (ret=  1) 00
> > [  452.424454] [drm:drm_dp_mst_topology_put_mstb [drm_kms_helper]] mstb
> > 00000000eec1a629 (0)
> > [  452.424457] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port
> > 00000000eeef3cfd (0)
> > [  452.424461] ------------[ cut here ]------------
> > [  452.424464] sysfs group 'power' not found for kobject 'drm_dp_aux5'
> > [  452.424471] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424473] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl
> > x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm
> > mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof
> > intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel
> > intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl
> > btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth
> > drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801
> > intel_xhci_usb_role_switch processor_thermal_device typec_ucsi
> > intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec
> > intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal
> > int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video
> > pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage
> > i2c_dev
> > [  452.424492] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted:
> > G           O      5.1.0Lyude-Test+ #1
> > [  452.424494] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W
> > (1.12 ) 04/09/2018
> > [  452.424496] RIP: 0010:sysfs_remove_group+0x76/0x80
> > [  452.424498] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc
> > ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff
> > <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> > [  452.424500] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> > [  452.424501] RAX: 0000000000000000 RBX: 0000000000000000 RCX:
> > 0000000000000006
> > [  452.424502] RDX: 0000000000000007 RSI: 0000000000000086 RDI:
> > ffff981fde2d5a00
> > [  452.424503] RBP: ffffffffa9ea12e0 R08: 0000000000000792 R09:
> > 0000000000000046
> > [  452.424504] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12:
> > ffff981fd5f77010
> > [  452.424505] R13: ffff981fd6ebbedc R14: dead000000000200 R15:
> > dead000000000100
> > [  452.424507] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000)
> > knlGS:0000000000000000
> > [  452.424508] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [  452.424509] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4:
> > 00000000003606e0
> > [  452.424510] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> > 0000000000000000
> > [  452.424511] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> > 0000000000000400
> > [  452.424512] Call Trace:
> > [  452.424516]  device_del+0x75/0x360
> > [  452.424518]  ? class_find_device+0x96/0xf0
> > [  452.424520]  device_unregister+0x16/0x60
> > [  452.424521]  device_destroy+0x3a/0x40
> > [  452.424525]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> > [  452.424534]  ? drm_dbg+0x87/0x90 [drm]
> > [  452.424538]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> > [  452.424543]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> > [  452.424547]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0
> > [drm_kms_helper]
> > [  452.424551]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> > [  452.424571]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> > [  452.424592]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> > [  452.424600]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> > [  452.424621]  intel_modeset_cleanup+0xc8/0x140 [i915]
> > [  452.424633]  i915_driver_unload+0xa8/0x130 [i915]
> > [  452.424645]  i915_pci_remove+0x1e/0x40 [i915]
> > [  452.424647]  pci_device_remove+0x3b/0xc0
> > [  452.424649]  device_release_driver_internal+0xe4/0x1d0
> > [  452.424651]  pci_stop_bus_device+0x69/0x90
> > [  452.424653]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> > [  452.424655]  remove_store+0x75/0x90
> > [  452.424656]  kernfs_fop_write+0x116/0x190
> > [  452.424658]  vfs_write+0xa5/0x1a0
> > [  452.424660]  ksys_write+0x57/0xd0
> > [  452.424663]  do_syscall_64+0x55/0x150
> > [  452.424665]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > [  452.424667] RIP: 0033:0x7f8cc1e7d038
> > [  452.424668] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00
> > f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05
> > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> > [  452.424670] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000001
> > [  452.424672] RAX: ffffffffffffffda RBX: 0000000000000002 RCX:
> > 00007f8cc1e7d038
> > [  452.424673] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI:
> > 0000000000000001
> > [  452.424674] RBP: 000056515aefbf00 R08: 000000000000000a R09:
> > 00007f8cc1f0ee80
> > [  452.424675] R10: 000000000000000a R11: 0000000000000246 R12:
> > 00007f8cc1f50780
> > [  452.424676] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15:
> > 0000000000000002
> > [  452.424678] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424680] ---[ end trace a1c11eaf054910a3 ]---
> > [  452.424751] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPMST] unregistering
> > [  452.424755] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port
> > 000000000f6aa5a3 (0)
> > [  452.424765] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 120 (1)
> > [  452.424770] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000eeef3cfd (1)
> > [  452.424773] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000eeef3cfd (0)
> > [  452.424776] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb
> > 00000000eec1a629 (4)
> > [  452.424783] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug
> > event
> > [  452.424790] ------------[ cut here ]------------
> > [  452.424791] sysfs group 'power' not found for kobject 'drm_dp_aux4'
> > [  452.424795] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424796] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl
> > x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm
> > mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof
> > intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel
> > intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl
> > btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth
> > drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801
> > intel_xhci_usb_role_switch processor_thermal_device typec_ucsi
> > intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec
> > intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal
> > int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video
> > pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage
> > i2c_dev
> > [  452.424809] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted:
> > G        W  O      5.1.0Lyude-Test+ #1
> > [  452.424811] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W
> > (1.12 ) 04/09/2018
> > [  452.424812] RIP: 0010:sysfs_remove_group+0x76/0x80
> > [  452.424813] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc
> > ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff
> > <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> > [  452.424815] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> > [  452.424816] RAX: 0000000000000000 RBX: 0000000000000000 RCX:
> > 0000000000000006
> > [  452.424817] RDX: 0000000000000007 RSI: 0000000000000086 RDI:
> > ffff981fde2d5a00
> > [  452.424818] RBP: ffffffffa9ea12e0 R08: 00000000000007d1 R09:
> > 0000000000000046
> > [  452.424820] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12:
> > ffff981fd50d0410
> > [  452.424821] R13: ffff981fd6ebbebc R14: dead000000000200 R15:
> > dead000000000100
> > [  452.424822] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000)
> > knlGS:0000000000000000
> > [  452.424823] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [  452.424824] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4:
> > 00000000003606e0
> > [  452.424825] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> > 0000000000000000
> > [  452.424826] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> > 0000000000000400
> > [  452.424827] Call Trace:
> > [  452.424829]  device_del+0x75/0x360
> > [  452.424830]  ? class_find_device+0x96/0xf0
> > [  452.424832]  device_unregister+0x16/0x60
> > [  452.424833]  device_destroy+0x3a/0x40
> > [  452.424837]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> > [  452.424841]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> > [  452.424845]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> > [  452.424849]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0
> > [drm_kms_helper]
> > [  452.424854]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> > [  452.424873]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> > [  452.424892]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> > [  452.424900]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> > [  452.424920]  intel_modeset_cleanup+0xc8/0x140 [i915]
> > [  452.424932]  i915_driver_unload+0xa8/0x130 [i915]
> > [  452.424943]  i915_pci_remove+0x1e/0x40 [i915]
> > [  452.424945]  pci_device_remove+0x3b/0xc0
> > [  452.424947]  device_release_driver_internal+0xe4/0x1d0
> > [  452.424948]  pci_stop_bus_device+0x69/0x90
> > [  452.424950]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> > [  452.424951]  remove_store+0x75/0x90
> > [  452.424953]  kernfs_fop_write+0x116/0x190
> > [  452.424954]  vfs_write+0xa5/0x1a0
> > [  452.424956]  ksys_write+0x57/0xd0
> > [  452.424957]  do_syscall_64+0x55/0x150
> > [  452.424959]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > [  452.424960] RIP: 0033:0x7f8cc1e7d038
> > [  452.424961] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00
> > f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05
> > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> > [  452.424963] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000001
> > [  452.424965] RAX: ffffffffffffffda RBX: 0000000000000002 RCX:
> > 00007f8cc1e7d038
> > [  452.424966] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI:
> > 0000000000000001
> > [  452.424967] RBP: 000056515aefbf00 R08: 000000000000000a R09:
> > 00007f8cc1f0ee80
> > [  452.424968] R10: 000000000000000a R11: 0000000000000246 R12:
> > 00007f8cc1f50780
> > [  452.424969] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15:
> > 0000000000000002
> > [  452.424971] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.424972] ---[ end trace a1c11eaf054910a4 ]---
> > [  452.424992] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPMST] unregistering
> > [  452.424997] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port
> > 00000000dde1b00a (0)
> > [  452.425006] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 117 (1)
> > [  452.425010] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 000000000f6aa5a3 (1)
> > [  452.425014] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 000000000f6aa5a3 (0)
> > [  452.425017] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb
> > 00000000eec1a629 (3)
> > [  452.425023] [drm:drm_sysfs_hotplug_event [drm]] generating hotplug
> > event
> > [  452.425028] ------------[ cut here ]------------
> > [  452.425029] sysfs group 'power' not found for kobject 'drm_dp_aux3'
> > [  452.425033] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.425034] Modules linked in: vfat fat elan_i2c i915(O) intel_rapl
> > x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt kvm
> > mei_wdt irqbypass iTCO_vendor_support crct10dif_pclmul wmi_bmof
> > intel_wmi_thunderbolt crc32_pclmul i2c_algo_bit ghash_clmulni_intel
> > intel_cstate drm_kms_helper(O) intel_uncore intel_rapl_perf btusb btrtl
> > btbcm syscopyarea btintel sysfillrect sysimgblt fb_sys_fops bluetooth
> > drm(O) joydev mei_me idma64 ucsi_acpi thunderbolt ecdh_generic i2c_i801
> > intel_xhci_usb_role_switch processor_thermal_device typec_ucsi
> > intel_lpss_pci intel_soc_dts_iosf mei roles intel_lpss typec
> > intel_pch_thermal wmi thinkpad_acpi ledtrig_audio rfkill int3403_thermal
> > int340x_thermal_zone int3400_thermal acpi_thermal_rel acpi_pad video
> > pcc_cpufreq crc32c_intel nvme serio_raw uas e1000e nvme_core usb_storage
> > i2c_dev
> > [  452.425047] CPU: 3 PID: 1887 Comm: unloadgpumod Tainted:
> > G        W  O      5.1.0Lyude-Test+ #1
> > [  452.425048] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W
> > (1.12 ) 04/09/2018
> > [  452.425050] RIP: 0010:sysfs_remove_group+0x76/0x80
> > [  452.425051] Code: 48 89 df 5b 5d 41 5c e9 f8 bc ff ff 48 89 df e8 d0 bc
> > ff ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 08 a5 0c aa e8 44 00 d6 ff
> > <0f> 0b 5b 5d 41 5c c3 0f 1f 00 0f 1f 44 00 00 48 85 f6 74 31 41 54
> > [  452.425053] RSP: 0018:ffffa8bb81b5fb28 EFLAGS: 00010282
> > [  452.425054] RAX: 0000000000000000 RBX: 0000000000000000 RCX:
> > 0000000000000006
> > [  452.425055] RDX: 0000000000000007 RSI: 0000000000000086 RDI:
> > ffff981fde2d5a00
> > [  452.425056] RBP: ffffffffa9ea12e0 R08: 000000000000080f R09:
> > 0000000000000046
> > [  452.425057] R10: 0000000000000727 R11: ffffa8bb81b5f9d0 R12:
> > ffff981fd50d1810
> > [  452.425058] R13: ffff981fd6ebbe1c R14: dead000000000200 R15:
> > dead000000000100
> > [  452.425059] FS:  00007f8cc1d8c740(0000) GS:ffff981fde2c0000(0000)
> > knlGS:0000000000000000
> > [  452.425061] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [  452.425062] CR2: 000055b19d079a08 CR3: 000000043b2a0002 CR4:
> > 00000000003606e0
> > [  452.425063] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> > 0000000000000000
> > [  452.425064] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> > 0000000000000400
> > [  452.425065] Call Trace:
> > [  452.425066]  device_del+0x75/0x360
> > [  452.425068]  ? class_find_device+0x96/0xf0
> > [  452.425069]  device_unregister+0x16/0x60
> > [  452.425070]  device_destroy+0x3a/0x40
> > [  452.425074]  drm_dp_aux_unregister_devnode+0xea/0x180 [drm_kms_helper]
> > [  452.425078]  drm_dp_mst_topology_put_port+0x5b/0x110 [drm_kms_helper]
> > [  452.425083]  drm_dp_mst_topology_put_mstb+0xb6/0x180 [drm_kms_helper]
> > [  452.425087]  drm_dp_mst_topology_mgr_set_mst+0x233/0x2b0
> > [drm_kms_helper]
> > [  452.425091]  drm_dp_mst_topology_mgr_destroy+0x18/0xa0 [drm_kms_helper]
> > [  452.425110]  intel_dp_encoder_flush_work+0x32/0xb0 [i915]
> > [  452.425128]  intel_ddi_encoder_destroy+0x32/0x70 [i915]
> > [  452.425137]  drm_mode_config_cleanup+0x51/0x2e0 [drm]
> > [  452.425157]  intel_modeset_cleanup+0xc8/0x140 [i915]
> > [  452.425168]  i915_driver_unload+0xa8/0x130 [i915]
> > [  452.425180]  i915_pci_remove+0x1e/0x40 [i915]
> > [  452.425182]  pci_device_remove+0x3b/0xc0
> > [  452.425183]  device_release_driver_internal+0xe4/0x1d0
> > [  452.425185]  pci_stop_bus_device+0x69/0x90
> > [  452.425186]  pci_stop_and_remove_bus_device_locked+0x16/0x30
> > [  452.425188]  remove_store+0x75/0x90
> > [  452.425189]  kernfs_fop_write+0x116/0x190
> > [  452.425191]  vfs_write+0xa5/0x1a0
> > [  452.425192]  ksys_write+0x57/0xd0
> > [  452.425194]  do_syscall_64+0x55/0x150
> > [  452.425195]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > [  452.425197] RIP: 0033:0x7f8cc1e7d038
> > [  452.425198] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00
> > f3 0f 1e fa 48 8d 05 e5 76 0d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05
> > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> > [  452.425199] RSP: 002b:00007ffce4321218 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000001
> > [  452.425201] RAX: ffffffffffffffda RBX: 0000000000000002 RCX:
> > 00007f8cc1e7d038
> > [  452.425202] RDX: 0000000000000002 RSI: 000056515aefbf00 RDI:
> > 0000000000000001
> > [  452.425203] RBP: 000056515aefbf00 R08: 000000000000000a R09:
> > 00007f8cc1f0ee80
> > [  452.425204] R10: 000000000000000a R11: 0000000000000246 R12:
> > 00007f8cc1f50780
> > [  452.425205] R13: 0000000000000002 R14: 00007f8cc1f4b740 R15:
> > 0000000000000002
> > [  452.425207] WARNING: CPU: 3 PID: 1887 at fs/sysfs/group.c:256
> > sysfs_remove_group+0x76/0x80
> > [  452.425208] ---[ end trace a1c11eaf054910a5 ]---
> > [  452.425282] [drm:drm_dp_aux_unregister_devnode [drm_kms_helper]]
> > drm_dp_aux_dev: aux [DPMST] unregistering
> > [  452.425288] [drm:drm_dp_mst_topology_put_port [drm_kms_helper]] port
> > 000000002ba3174e (0)
> > [  452.425292] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 000000002ba3174e (0)
> > [  452.425295] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb
> > 00000000eec1a629 (2)
> > [  452.425299] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb
> > 00000000eec1a629 (1)
> > [  452.425311] [drm:drm_mode_object_put.part.3 [drm]] OBJ ID: 86 (1)
> > [  452.425318] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000dde1b00a (1)
> > [  452.425365] [drm:drm_dp_mst_put_port_malloc [drm_kms_helper]] port
> > 00000000dde1b00a (0)
> > [  452.425368] [drm:drm_dp_mst_put_mstb_malloc [drm_kms_helper]] mstb
> > 00000000eec1a629 (0)
> > 
> > So, we need to move the drm_dp_aux_register_devnode() call above the
> > connector
> > registration callback. Same goes for the port->aux.dev = port->connector-
> > > kdev; assignment that you do in patch 3/7 (and of course, you can remove
> > > the
> > connector registration status check there now).
> > 
> > > +
> > > +             drm_dp_aux_register_devnode(&port->aux);
> > >        }
> > > 
> > >   out:
> > > @@ -1404,7 +1454,6 @@ static bool drm_dp_validate_guid(struct
> > > drm_dp_mst_topology_mgr *mgr,
> > >        return false;
> > >   }
> > > 
> > > -#if 0
> > >   static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8
> > > port_num,
> > > u32 offset, u8 num_bytes)
> > >   {
> > >        struct drm_dp_sideband_msg_req_body req;
> > > @@ -1417,7 +1466,6 @@ static int build_dpcd_read(struct
> > > drm_dp_sideband_msg_tx *msg, u8 port_num, u32
> > > 
> > >        return 0;
> > >   }
> > > -#endif
> > > 
> > >   static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr
> > > *mgr,
> > >                                    bool up, u8 *msg, int len)
> > > @@ -1994,26 +2042,55 @@ int drm_dp_update_payload_part2(struct
> > > drm_dp_mst_topology_mgr *mgr)
> > >   }
> > >   EXPORT_SYMBOL(drm_dp_update_payload_part2);
> > > 
> > > -#if 0 /* unused as of yet */
> > >   static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
> > >                                 struct drm_dp_mst_port *port,
> > > -                              int offset, int size)
> > > +                              int offset, int size, u8 *bytes)
> > >   {
> > >        int len;
> > > +     int ret = 0;
> > >        struct drm_dp_sideband_msg_tx *txmsg;
> > > +     struct drm_dp_mst_branch *mstb;
> > > +
> > > +     mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
> > > +     if (!mstb)
> > > +             return -EINVAL;
> > > 
> > >        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
> > > -     if (!txmsg)
> > > -             return -ENOMEM;
> > > +     if (!txmsg) {
> > > +             ret = -ENOMEM;
> > > +             goto fail_put;
> > > +     }
> > > 
> > > -     len = build_dpcd_read(txmsg, port->port_num, 0, 8);
> > > +     len = build_dpcd_read(txmsg, port->port_num, offset, size);
> > >        txmsg->dst = port->parent;
> > > 
> > >        drm_dp_queue_down_tx(mgr, txmsg);
> > > 
> > > -     return 0;
> > > +     ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
> > > +     if (ret < 0)
> > > +             goto fail_free;
> > > +
> > > +     /* DPCD read should never be NACKed */
> > > +     if (WARN_ON_ONCE(txmsg->reply.reply_type == 1)) {
> > > +             ret = -EIO;
> > > +             goto fail_free;
> > > +     }
> > > +
> > > +     if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) {
> > > +             ret = -EPROTO;
> > > +             goto fail_free;
> > > +     }
> > > +
> > > +     ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes,
> > > size);
> > > +     memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret);
> > > +
> > > +fail_free:
> > > +     kfree(txmsg);
> > > +fail_put:
> > > +     drm_dp_put_mst_branch_device(mstb);
> > > +
> > > +     return ret;
> > >   }
> > > -#endif
> > > 
> > >   static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
> > >                                  struct drm_dp_mst_port *port,
> > > @@ -2041,9 +2118,9 @@ static int drm_dp_send_dpcd_write(struct
> > > drm_dp_mst_topology_mgr *mgr,
> > > 
> > >        ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
> > >        if (ret > 0) {
> > > -             if (txmsg->reply.reply_type == 1) {
> > > -                     ret = -EINVAL;
> > > -             } else
> > > +             if (txmsg->reply.reply_type == 1)
> > > +                     ret = -EIO;
> > > +             else
> > >                        ret = 0;
> > >        }
> > >        kfree(txmsg);
> > > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> > > index 509667e..6dea76a 100644
> > > --- a/include/drm/drm_dp_helper.h
> > > +++ b/include/drm/drm_dp_helper.h
> > > @@ -1265,6 +1265,10 @@ struct drm_dp_aux {
> > >         * @cec: struct containing fields used for CEC-Tunneling-over-
> > > AUX.
> > >         */
> > >        struct drm_dp_aux_cec cec;
> > > +     /**
> > > +      * @is_remote: Is this "AUX CH" actually using sideband messaging.
> > > +      */
> > > +     bool is_remote;
> > >   };
> > > 
> > >   ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
> > > diff --git a/include/drm/drm_dp_mst_helper.h
> > > b/include/drm/drm_dp_mst_helper.h
> > > index 371cc28..30f8c11 100644
> > > --- a/include/drm/drm_dp_mst_helper.h
> > > +++ b/include/drm/drm_dp_mst_helper.h
> > > @@ -615,6 +615,12 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
> > > 
> > >   void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr
> > > *mgr);
> > >   int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr
> > > *mgr);
> > > +
> > > +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
> > > +                          unsigned int offset, void *buffer, size_t
> > > size);
> > > +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
> > > +                           unsigned int offset, void *buffer, size_t
> > > size);
> > > +
> > >   struct drm_dp_mst_topology_state
> > > *drm_atomic_get_mst_topology_state(struct
> > > drm_atomic_state *state,
> > >                                                                    struc
> > > t
> > > drm_dp_mst_topology_mgr *mgr);
> > >   int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
> > --
> > Cheers,
> >          Lyude Paul
> >
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c
index 6d84611..01c02b9 100644
--- a/drivers/gpu/drm/drm_dp_aux_dev.c
+++ b/drivers/gpu/drm/drm_dp_aux_dev.c
@@ -34,6 +34,7 @@ 
 #include <linux/uaccess.h>
 #include <linux/uio.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drmP.h>
 
@@ -114,6 +115,7 @@  static ssize_t name_show(struct device *dev,
 
 	return res;
 }
+
 static DEVICE_ATTR_RO(name);
 
 static struct attribute *drm_dp_aux_attrs[] = {
@@ -160,7 +162,11 @@  static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 			break;
 		}
 
-		res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
+		if (aux_dev->aux->is_remote)
+			res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf, todo);
+		else
+			res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo);
+
 		if (res <= 0)
 			break;
 
@@ -207,7 +213,11 @@  static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
 			break;
 		}
 
-		res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
+		if (aux_dev->aux->is_remote)
+			res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf, todo);
+		else
+			res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo);
+
 		if (res <= 0)
 			break;
 
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 2ab16c9..54da68e 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -35,6 +35,8 @@ 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 
+#include "drm_crtc_helper_internal.h"
+
 /**
  * DOC: dp mst helper
  *
@@ -52,6 +54,9 @@  static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr,
 				     int id,
 				     struct drm_dp_payload *payload);
 
+static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
+				 struct drm_dp_mst_port *port,
+				 int offset, int size, u8 *bytes);
 static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
 				  struct drm_dp_mst_port *port,
 				  int offset, int size, u8 *bytes);
@@ -941,6 +946,8 @@  static void drm_dp_destroy_port(struct kref *kref)
 	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
 
 	if (!port->input) {
+		drm_dp_aux_unregister_devnode(&port->aux);
+
 		port->vcpi.num_slots = 0;
 
 		kfree(port->cached_edid);
@@ -1095,6 +1102,46 @@  static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
 	return send_link;
 }
 
+/**
+ * drm_dp_mst_dpcd_read() - read a series of bytes from the DPCD via sideband
+ * @aux: Fake sideband AUX CH
+ * @offset: address of the (first) register to read
+ * @buffer: buffer to store the register values
+ * @size: number of bytes in @buffer
+ *
+ * Performs the same functionality for remote devices via
+ * sideband messaging as drm_dp_dpcd_read() does for local
+ * devices via actual AUX CH.
+ */
+ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
+			     unsigned int offset, void *buffer, size_t size)
+{
+	struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, aux);
+
+	return drm_dp_send_dpcd_read(port->mgr, port,
+				     offset, size, buffer);
+}
+
+/**
+ * drm_dp_mst_dpcd_write() - write a series of bytes to the DPCD via sideband
+ * @aux: Fake sideband AUX CH
+ * @offset: address of the (first) register to write
+ * @buffer: buffer containing the values to write
+ * @size: number of bytes in @buffer
+ *
+ * Performs the same functionality for remote devices via
+ * sideband messaging as drm_dp_dpcd_write() does for local
+ * devices via actual AUX CH.
+ */
+ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
+			      unsigned int offset, void *buffer, size_t size)
+{
+	struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, aux);
+
+	return drm_dp_send_dpcd_write(port->mgr, port,
+				      offset, size, buffer);
+}
+
 static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
 {
 	int ret;
@@ -1158,6 +1205,7 @@  static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
 		port->mgr = mstb->mgr;
 		port->aux.name = "DPMST";
 		port->aux.dev = dev->dev;
+		port->aux.is_remote = true;
 		created = true;
 	} else {
 		old_pdt = port->pdt;
@@ -1188,7 +1236,7 @@  static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
 				drm_dp_send_enum_path_resources(mstb->mgr, mstb, port);
 		} else {
 			port->available_pbn = 0;
-			}
+		}
 	}
 
 	if (old_pdt != port->pdt && !port->input) {
@@ -1220,6 +1268,8 @@  static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
 			drm_connector_set_tile_property(port->connector);
 		}
 		(*mstb->mgr->cbs->register_connector)(port->connector);
+
+		drm_dp_aux_register_devnode(&port->aux);
 	}
 
 out:
@@ -1404,7 +1454,6 @@  static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
 	return false;
 }
 
-#if 0
 static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes)
 {
 	struct drm_dp_sideband_msg_req_body req;
@@ -1417,7 +1466,6 @@  static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32
 
 	return 0;
 }
-#endif
 
 static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr,
 				    bool up, u8 *msg, int len)
@@ -1994,26 +2042,55 @@  int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
 }
 EXPORT_SYMBOL(drm_dp_update_payload_part2);
 
-#if 0 /* unused as of yet */
 static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
 				 struct drm_dp_mst_port *port,
-				 int offset, int size)
+				 int offset, int size, u8 *bytes)
 {
 	int len;
+	int ret = 0;
 	struct drm_dp_sideband_msg_tx *txmsg;
+	struct drm_dp_mst_branch *mstb;
+
+	mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
+	if (!mstb)
+		return -EINVAL;
 
 	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
-	if (!txmsg)
-		return -ENOMEM;
+	if (!txmsg) {
+		ret = -ENOMEM;
+		goto fail_put;
+	}
 
-	len = build_dpcd_read(txmsg, port->port_num, 0, 8);
+	len = build_dpcd_read(txmsg, port->port_num, offset, size);
 	txmsg->dst = port->parent;
 
 	drm_dp_queue_down_tx(mgr, txmsg);
 
-	return 0;
+	ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
+	if (ret < 0)
+		goto fail_free;
+
+	/* DPCD read should never be NACKed */
+	if (WARN_ON_ONCE(txmsg->reply.reply_type == 1)) {
+		ret = -EIO;
+		goto fail_free;
+	}
+
+	if (txmsg->reply.u.remote_dpcd_read_ack.num_bytes != size) {
+		ret = -EPROTO;
+		goto fail_free;
+	}
+
+	ret = min_t(size_t, txmsg->reply.u.remote_dpcd_read_ack.num_bytes, size);
+	memcpy(bytes, txmsg->reply.u.remote_dpcd_read_ack.bytes, ret);
+
+fail_free:
+	kfree(txmsg);
+fail_put:
+	drm_dp_put_mst_branch_device(mstb);
+
+	return ret;
 }
-#endif
 
 static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
 				  struct drm_dp_mst_port *port,
@@ -2041,9 +2118,9 @@  static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
 
 	ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
 	if (ret > 0) {
-		if (txmsg->reply.reply_type == 1) {
-			ret = -EINVAL;
-		} else
+		if (txmsg->reply.reply_type == 1)
+			ret = -EIO;
+		else
 			ret = 0;
 	}
 	kfree(txmsg);
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 509667e..6dea76a 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -1265,6 +1265,10 @@  struct drm_dp_aux {
 	 * @cec: struct containing fields used for CEC-Tunneling-over-AUX.
 	 */
 	struct drm_dp_aux_cec cec;
+	/**
+	 * @is_remote: Is this "AUX CH" actually using sideband messaging.
+	 */
+	bool is_remote;
 };
 
 ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 371cc28..30f8c11 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -615,6 +615,12 @@  void drm_dp_mst_dump_topology(struct seq_file *m,
 
 void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr);
 int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
+
+ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
+			     unsigned int offset, void *buffer, size_t size);
+ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
+			      unsigned int offset, void *buffer, size_t size);
+
 struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
 								    struct drm_dp_mst_topology_mgr *mgr);
 int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,