diff mbox series

[2/2] drm/dp_mst: Handle SST-only branch device case

Message ID 20200108084416.6296-3-Wayne.Lin@amd.com (mailing list archive)
State New, archived
Headers show
Series Take SST-only branch device into account | expand

Commit Message

Lin, Wayne Jan. 8, 2020, 8:44 a.m. UTC
[Why]
While handling LINK_ADDRESS reply, current code expects a peer device
can handle sideband message once the peer device type is reported as
DP_PEER_DEVICE_MST_BRANCHING. However, when the connected device is
a SST branch case, it can't handle the sideband message(MST_CAP=0 in
DPCD 00021h).

Current code will try to send LINK_ADDRESS to SST branch device and end
up with message timeout and monitor can't display normally. As the
result of that, we should take SST branch device into account.

[How]
According to DP 1.4 spec, we can use Peer_Device_Type as
DP_PEER_DEVICE_MST_BRANCHING and Message_Capability_Status as 0 to
indicate peer device as a SST-only branch device.

Fix following:
- Take SST-only branch device case into account in
drm_dp_port_set_pdt() and add a new parameter 'new_mcs'. Take sst branch
device case as the same case as DP_PEER_DEVICE_DP_LEGACY_CONV and
DP_PEER_DEVICE_SST_SINK. All original handling logics remain.
- Take SST-only branch device case into account in
drm_dp_mst_port_add_connector().
- Fix some parts in drm_dp_mst_handle_link_address_port() to have SST
branch device case into consideration.
- Fix the arguments of drm_dp_port_set_pdt() in
drm_dp_mst_handle_conn_stat().
- Have SST branch device also report
connector_status_connected when the ddps is true
in drm_dp_mst_detect_port()
- Fix the arguments of drm_dp_port_set_pdt() in
drm_dp_delayed_destroy_port()

Fixes: c485e2c97dae ("drm/dp_mst: Refactor pdt setup/teardown, add more locking")
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Lyude Paul <lyude@redhat.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 131 +++++++++++++-------------
 1 file changed, 68 insertions(+), 63 deletions(-)

Comments

Lyude Paul Jan. 14, 2020, 9:18 p.m. UTC | #1
On Wed, 2020-01-08 at 16:44 +0800, Wayne Lin wrote:
> [Why]
> While handling LINK_ADDRESS reply, current code expects a peer device
> can handle sideband message once the peer device type is reported as
> DP_PEER_DEVICE_MST_BRANCHING. However, when the connected device is
> a SST branch case, it can't handle the sideband message(MST_CAP=0 in
> DPCD 00021h).
> 
> Current code will try to send LINK_ADDRESS to SST branch device and end
> up with message timeout and monitor can't display normally. As the
> result of that, we should take SST branch device into account.
> 
> [How]
> According to DP 1.4 spec, we can use Peer_Device_Type as
> DP_PEER_DEVICE_MST_BRANCHING and Message_Capability_Status as 0 to
> indicate peer device as a SST-only branch device.
> 
> Fix following:
> - Take SST-only branch device case into account in
> drm_dp_port_set_pdt() and add a new parameter 'new_mcs'. Take sst branch
> device case as the same case as DP_PEER_DEVICE_DP_LEGACY_CONV and
> DP_PEER_DEVICE_SST_SINK. All original handling logics remain.
> - Take SST-only branch device case into account in
> drm_dp_mst_port_add_connector().
> - Fix some parts in drm_dp_mst_handle_link_address_port() to have SST
> branch device case into consideration.
> - Fix the arguments of drm_dp_port_set_pdt() in
> drm_dp_mst_handle_conn_stat().
> - Have SST branch device also report
> connector_status_connected when the ddps is true
> in drm_dp_mst_detect_port()
> - Fix the arguments of drm_dp_port_set_pdt() in
> drm_dp_delayed_destroy_port()
> 
> Fixes: c485e2c97dae ("drm/dp_mst: Refactor pdt setup/teardown, add more
> locking")
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Harry Wentland <hwentlan@amd.com>
> Cc: Lyude Paul <lyude@redhat.com>
> Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
> ---
>  drivers/gpu/drm/drm_dp_mst_topology.c | 131 +++++++++++++-------------
>  1 file changed, 68 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> b/drivers/gpu/drm/drm_dp_mst_topology.c
> index 8f54b241db08..4395d5cc0645 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -1934,73 +1934,74 @@ static bool drm_dp_mst_is_dp_mst_end_device(u8 pdt,
> bool mcs)
>  	return true;
>  }
>  
> -static int drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt)
> +static int
> +drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
> +		    bool new_mcs)
>  {
>  	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
>  	struct drm_dp_mst_branch *mstb;
>  	u8 rad[8], lct;
>  	int ret = 0;
>  
> -	if (port->pdt == new_pdt)
> +	if (port->pdt == new_pdt && port->mcs == new_mcs)
>  		return 0;
>  
>  	/* Teardown the old pdt, if there is one */
> -	switch (port->pdt) {
> -	case DP_PEER_DEVICE_DP_LEGACY_CONV:
> -	case DP_PEER_DEVICE_SST_SINK:
> -		/*
> -		 * If the new PDT would also have an i2c bus, don't bother
> -		 * with reregistering it
> -		 */
> -		if (new_pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
> -		    new_pdt == DP_PEER_DEVICE_SST_SINK) {
> -			port->pdt = new_pdt;
> -			return 0;
> -		}
> +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> +			/*
> +			 * If the new PDT would also have an i2c bus,
> +			 * don't bother with reregistering it
> +			 */
> +			if (new_pdt != DP_PEER_DEVICE_NONE &&
> +			    drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs))
> {
> +				port->pdt = new_pdt;
> +				port->mcs = new_mcs;
> +				return 0;
> +			}
>  
> -		/* remove i2c over sideband */
> -		drm_dp_mst_unregister_i2c_bus(&port->aux);
> -		break;
> -	case DP_PEER_DEVICE_MST_BRANCHING:
> -		mutex_lock(&mgr->lock);
> -		drm_dp_mst_topology_put_mstb(port->mstb);
> -		port->mstb = NULL;
> -		mutex_unlock(&mgr->lock);
> -		break;
> +			/* remove i2c over sideband */
> +			drm_dp_mst_unregister_i2c_bus(&port->aux);
> +		} else {
> +			mutex_lock(&mgr->lock);
> +			drm_dp_mst_topology_put_mstb(port->mstb);
> +			port->mstb = NULL;
> +			mutex_unlock(&mgr->lock);
> +		}
>  	}
>  
>  	port->pdt = new_pdt;
> -	switch (port->pdt) {
> -	case DP_PEER_DEVICE_DP_LEGACY_CONV:
> -	case DP_PEER_DEVICE_SST_SINK:
> -		/* add i2c over sideband */
> -		ret = drm_dp_mst_register_i2c_bus(&port->aux);
> -		break;
> +	port->mcs = new_mcs;
>  
> -	case DP_PEER_DEVICE_MST_BRANCHING:
> -		lct = drm_dp_calculate_rad(port, rad);
> -		mstb = drm_dp_add_mst_branch_device(lct, rad);
> -		if (!mstb) {
> -			ret = -ENOMEM;
> -			DRM_ERROR("Failed to create MSTB for port %p", port);
> -			goto out;
> -		}
> +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> +			/* add i2c over sideband */
> +			ret = drm_dp_mst_register_i2c_bus(&port->aux);
> +		} else {
> +			lct = drm_dp_calculate_rad(port, rad);
> +			mstb = drm_dp_add_mst_branch_device(lct, rad);
> +			if (!mstb) {
> +				ret = -ENOMEM;
> +				DRM_ERROR("Failed to create MSTB for port %p",
> +					  port);
> +				goto out;
> +			}
>  
> -		mutex_lock(&mgr->lock);
> -		port->mstb = mstb;
> -		mstb->mgr = port->mgr;
> -		mstb->port_parent = port;
> +			mutex_lock(&mgr->lock);
> +			port->mstb = mstb;
> +			mstb->mgr = port->mgr;
> +			mstb->port_parent = port;
>  
> -		/*
> -		 * Make sure this port's memory allocation stays
> -		 * around until its child MSTB releases it
> -		 */
> -		drm_dp_mst_get_port_malloc(port);
> -		mutex_unlock(&mgr->lock);
> +			/*
> +			 * Make sure this port's memory allocation stays
> +			 * around until its child MSTB releases it
> +			 */
> +			drm_dp_mst_get_port_malloc(port);
> +			mutex_unlock(&mgr->lock);
>  
> -		/* And make sure we send a link address for this */
> -		ret = 1;
> -		break;
> +			/* And make sure we send a link address for this */
> +			ret = 1;
> +		}
>  	}
>  
>  out:
> @@ -2153,12 +2154,12 @@ drm_dp_mst_port_add_connector(struct
> drm_dp_mst_branch *mstb,
>  		goto error;
>  	}
>  
> -	if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
> -	     port->pdt == DP_PEER_DEVICE_SST_SINK) &&
> -	    port->port_num >= DP_MST_LOGICAL_PORT_0) {
> -		port->cached_edid = drm_get_edid(port->connector,
> -						 &port->aux.ddc);
> -		drm_connector_set_tile_property(port->connector);
> +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> +			port->cached_edid = drm_get_edid(port->connector,
> +							 &port->aux.ddc);
> +			drm_connector_set_tile_property(port->connector);
> +		}

I'd combine these two if statements here into one, otherwise this looks great.
Thank you for all of the great fixes recently :)

Reviewed-by: Lyude Paul <lyude@redhat.com>


>  	}
>  
>  	mgr->cbs->register_connector(port->connector);
> @@ -2223,6 +2224,7 @@ drm_dp_mst_handle_link_address_port(struct
> drm_dp_mst_branch *mstb,
>  	struct drm_dp_mst_port *port;
>  	int old_ddps = 0, ret;
>  	u8 new_pdt = DP_PEER_DEVICE_NONE;
> +	bool new_mcs = 0;
>  	bool created = false, send_link_addr = false, changed = false;
>  
>  	port = drm_dp_get_port(mstb, port_msg->port_number);
> @@ -2267,7 +2269,7 @@ drm_dp_mst_handle_link_address_port(struct
> drm_dp_mst_branch *mstb,
>  	port->input = port_msg->input_port;
>  	if (!port->input)
>  		new_pdt = port_msg->peer_device_type;
> -	port->mcs = port_msg->mcs;
> +	new_mcs = port_msg->mcs;
>  	port->ddps = port_msg->ddps;
>  	port->ldps = port_msg->legacy_device_plug_status;
>  	port->dpcd_rev = port_msg->dpcd_revision;
> @@ -2295,7 +2297,7 @@ drm_dp_mst_handle_link_address_port(struct
> drm_dp_mst_branch *mstb,
>  		}
>  	}
>  
> -	ret = drm_dp_port_set_pdt(port, new_pdt);
> +	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
>  	if (ret == 1) {
>  		send_link_addr = true;
>  	} else if (ret < 0) {
> @@ -2309,7 +2311,8 @@ drm_dp_mst_handle_link_address_port(struct
> drm_dp_mst_branch *mstb,
>  	 * we're coming out of suspend. In this case, always resend the link
>  	 * address if there's an MSTB on this port
>  	 */
> -	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING)
> +	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
> +	    port->mcs)
>  		send_link_addr = true;
>  
>  	if (port->connector)
> @@ -2346,6 +2349,7 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> *mstb,
>  	struct drm_dp_mst_port *port;
>  	int old_ddps, old_input, ret, i;
>  	u8 new_pdt;
> +	bool new_mcs;
>  	bool dowork = false, create_connector = false;
>  
>  	port = drm_dp_get_port(mstb, conn_stat->port_number);
> @@ -2377,7 +2381,6 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> *mstb,
>  	old_ddps = port->ddps;
>  	old_input = port->input;
>  	port->input = conn_stat->input_port;
> -	port->mcs = conn_stat->message_capability_status;
>  	port->ldps = conn_stat->legacy_device_plug_status;
>  	port->ddps = conn_stat->displayport_device_plug_status;
>  
> @@ -2390,8 +2393,8 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> *mstb,
>  	}
>  
>  	new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat-
> >peer_device_type;
> -
> -	ret = drm_dp_port_set_pdt(port, new_pdt);
> +	new_mcs = conn_stat->message_capability_status;
> +	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
>  	if (ret == 1) {
>  		dowork = true;
>  	} else if (ret < 0) {
> @@ -3958,6 +3961,8 @@ drm_dp_mst_detect_port(struct drm_connector
> *connector,
>  	switch (port->pdt) {
>  	case DP_PEER_DEVICE_NONE:
>  	case DP_PEER_DEVICE_MST_BRANCHING:
> +		if (!port->mcs)
> +			ret = connector_status_connected;
>  		break;
>  
>  	case DP_PEER_DEVICE_SST_SINK:
> @@ -4597,7 +4602,7 @@ drm_dp_delayed_destroy_port(struct drm_dp_mst_port
> *port)
>  	if (port->connector)
>  		port->mgr->cbs->destroy_connector(port->mgr, port->connector);
>  
> -	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE);
> +	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
>  	drm_dp_mst_put_port_malloc(port);
>  }
>
Lin, Wayne Jan. 15, 2020, 2:43 a.m. UTC | #2
[AMD Public Use]



> -----Original Message-----
> From: Lyude Paul <lyude@redhat.com>
> Sent: Wednesday, January 15, 2020 5:19 AM
> To: Lin, Wayne <Wayne.Lin@amd.com>; dri-devel@lists.freedesktop.org;
> amd-gfx@lists.freedesktop.org
> Cc: Kazlauskas, Nicholas <Nicholas.Kazlauskas@amd.com>; Wentland, Harry
> <Harry.Wentland@amd.com>; Zuo, Jerry <Jerry.Zuo@amd.com>; Ville Syrjälä
> <ville.syrjala@linux.intel.com>; Wentland, Harry <Harry.Wentland@amd.com>
> Subject: Re: [PATCH 2/2] drm/dp_mst: Handle SST-only branch device case
> 
> On Wed, 2020-01-08 at 16:44 +0800, Wayne Lin wrote:
> > [Why]
> > While handling LINK_ADDRESS reply, current code expects a peer device
> > can handle sideband message once the peer device type is reported as
> > DP_PEER_DEVICE_MST_BRANCHING. However, when the connected device
> is a
> > SST branch case, it can't handle the sideband message(MST_CAP=0 in
> > DPCD 00021h).
> >
> > Current code will try to send LINK_ADDRESS to SST branch device and
> > end up with message timeout and monitor can't display normally. As the
> > result of that, we should take SST branch device into account.
> >
> > [How]
> > According to DP 1.4 spec, we can use Peer_Device_Type as
> > DP_PEER_DEVICE_MST_BRANCHING and Message_Capability_Status as 0 to
> > indicate peer device as a SST-only branch device.
> >
> > Fix following:
> > - Take SST-only branch device case into account in
> > drm_dp_port_set_pdt() and add a new parameter 'new_mcs'. Take sst
> > branch device case as the same case as
> DP_PEER_DEVICE_DP_LEGACY_CONV
> > and DP_PEER_DEVICE_SST_SINK. All original handling logics remain.
> > - Take SST-only branch device case into account in
> > drm_dp_mst_port_add_connector().
> > - Fix some parts in drm_dp_mst_handle_link_address_port() to have SST
> > branch device case into consideration.
> > - Fix the arguments of drm_dp_port_set_pdt() in
> > drm_dp_mst_handle_conn_stat().
> > - Have SST branch device also report
> > connector_status_connected when the ddps is true in
> > drm_dp_mst_detect_port()
> > - Fix the arguments of drm_dp_port_set_pdt() in
> > drm_dp_delayed_destroy_port()
> >
> > Fixes: c485e2c97dae ("drm/dp_mst: Refactor pdt setup/teardown, add
> > more
> > locking")
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Harry Wentland <hwentlan@amd.com>
> > Cc: Lyude Paul <lyude@redhat.com>
> > Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
> > ---
> >  drivers/gpu/drm/drm_dp_mst_topology.c | 131
> > +++++++++++++-------------
> >  1 file changed, 68 insertions(+), 63 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> > b/drivers/gpu/drm/drm_dp_mst_topology.c
> > index 8f54b241db08..4395d5cc0645 100644
> > --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> > @@ -1934,73 +1934,74 @@ static bool
> drm_dp_mst_is_dp_mst_end_device(u8
> > pdt, bool mcs)
> >  	return true;
> >  }
> >
> > -static int drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8
> > new_pdt)
> > +static int
> > +drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
> > +		    bool new_mcs)
> >  {
> >  	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
> >  	struct drm_dp_mst_branch *mstb;
> >  	u8 rad[8], lct;
> >  	int ret = 0;
> >
> > -	if (port->pdt == new_pdt)
> > +	if (port->pdt == new_pdt && port->mcs == new_mcs)
> >  		return 0;
> >
> >  	/* Teardown the old pdt, if there is one */
> > -	switch (port->pdt) {
> > -	case DP_PEER_DEVICE_DP_LEGACY_CONV:
> > -	case DP_PEER_DEVICE_SST_SINK:
> > -		/*
> > -		 * If the new PDT would also have an i2c bus, don't bother
> > -		 * with reregistering it
> > -		 */
> > -		if (new_pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
> > -		    new_pdt == DP_PEER_DEVICE_SST_SINK) {
> > -			port->pdt = new_pdt;
> > -			return 0;
> > -		}
> > +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> > +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> > +			/*
> > +			 * If the new PDT would also have an i2c bus,
> > +			 * don't bother with reregistering it
> > +			 */
> > +			if (new_pdt != DP_PEER_DEVICE_NONE &&
> > +			    drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs))
> > {
> > +				port->pdt = new_pdt;
> > +				port->mcs = new_mcs;
> > +				return 0;
> > +			}
> >
> > -		/* remove i2c over sideband */
> > -		drm_dp_mst_unregister_i2c_bus(&port->aux);
> > -		break;
> > -	case DP_PEER_DEVICE_MST_BRANCHING:
> > -		mutex_lock(&mgr->lock);
> > -		drm_dp_mst_topology_put_mstb(port->mstb);
> > -		port->mstb = NULL;
> > -		mutex_unlock(&mgr->lock);
> > -		break;
> > +			/* remove i2c over sideband */
> > +			drm_dp_mst_unregister_i2c_bus(&port->aux);
> > +		} else {
> > +			mutex_lock(&mgr->lock);
> > +			drm_dp_mst_topology_put_mstb(port->mstb);
> > +			port->mstb = NULL;
> > +			mutex_unlock(&mgr->lock);
> > +		}
> >  	}
> >
> >  	port->pdt = new_pdt;
> > -	switch (port->pdt) {
> > -	case DP_PEER_DEVICE_DP_LEGACY_CONV:
> > -	case DP_PEER_DEVICE_SST_SINK:
> > -		/* add i2c over sideband */
> > -		ret = drm_dp_mst_register_i2c_bus(&port->aux);
> > -		break;
> > +	port->mcs = new_mcs;
> >
> > -	case DP_PEER_DEVICE_MST_BRANCHING:
> > -		lct = drm_dp_calculate_rad(port, rad);
> > -		mstb = drm_dp_add_mst_branch_device(lct, rad);
> > -		if (!mstb) {
> > -			ret = -ENOMEM;
> > -			DRM_ERROR("Failed to create MSTB for port %p", port);
> > -			goto out;
> > -		}
> > +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> > +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> > +			/* add i2c over sideband */
> > +			ret = drm_dp_mst_register_i2c_bus(&port->aux);
> > +		} else {
> > +			lct = drm_dp_calculate_rad(port, rad);
> > +			mstb = drm_dp_add_mst_branch_device(lct, rad);
> > +			if (!mstb) {
> > +				ret = -ENOMEM;
> > +				DRM_ERROR("Failed to create MSTB for port %p",
> > +					  port);
> > +				goto out;
> > +			}
> >
> > -		mutex_lock(&mgr->lock);
> > -		port->mstb = mstb;
> > -		mstb->mgr = port->mgr;
> > -		mstb->port_parent = port;
> > +			mutex_lock(&mgr->lock);
> > +			port->mstb = mstb;
> > +			mstb->mgr = port->mgr;
> > +			mstb->port_parent = port;
> >
> > -		/*
> > -		 * Make sure this port's memory allocation stays
> > -		 * around until its child MSTB releases it
> > -		 */
> > -		drm_dp_mst_get_port_malloc(port);
> > -		mutex_unlock(&mgr->lock);
> > +			/*
> > +			 * Make sure this port's memory allocation stays
> > +			 * around until its child MSTB releases it
> > +			 */
> > +			drm_dp_mst_get_port_malloc(port);
> > +			mutex_unlock(&mgr->lock);
> >
> > -		/* And make sure we send a link address for this */
> > -		ret = 1;
> > -		break;
> > +			/* And make sure we send a link address for this */
> > +			ret = 1;
> > +		}
> >  	}
> >
> >  out:
> > @@ -2153,12 +2154,12 @@ drm_dp_mst_port_add_connector(struct
> > drm_dp_mst_branch *mstb,
> >  		goto error;
> >  	}
> >
> > -	if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
> > -	     port->pdt == DP_PEER_DEVICE_SST_SINK) &&
> > -	    port->port_num >= DP_MST_LOGICAL_PORT_0) {
> > -		port->cached_edid = drm_get_edid(port->connector,
> > -						 &port->aux.ddc);
> > -		drm_connector_set_tile_property(port->connector);
> > +	if (port->pdt != DP_PEER_DEVICE_NONE) {
> > +		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
> > +			port->cached_edid = drm_get_edid(port->connector,
> > +							 &port->aux.ddc);
> > +			drm_connector_set_tile_property(port->connector);
> > +		}
> 
> I'd combine these two if statements here into one, otherwise this looks great.
> Thank you for all of the great fixes recently :)
> 
> Reviewed-by: Lyude Paul <lyude@redhat.com>
Thanks for your time!
I will fix it in the new version.
Thanks.
> 
> 
> >  	}
> >
> >  	mgr->cbs->register_connector(port->connector);
> > @@ -2223,6 +2224,7 @@ drm_dp_mst_handle_link_address_port(struct
> > drm_dp_mst_branch *mstb,
> >  	struct drm_dp_mst_port *port;
> >  	int old_ddps = 0, ret;
> >  	u8 new_pdt = DP_PEER_DEVICE_NONE;
> > +	bool new_mcs = 0;
> >  	bool created = false, send_link_addr = false, changed = false;
> >
> >  	port = drm_dp_get_port(mstb, port_msg->port_number); @@ -2267,7
> > +2269,7 @@ drm_dp_mst_handle_link_address_port(struct
> > drm_dp_mst_branch *mstb,
> >  	port->input = port_msg->input_port;
> >  	if (!port->input)
> >  		new_pdt = port_msg->peer_device_type;
> > -	port->mcs = port_msg->mcs;
> > +	new_mcs = port_msg->mcs;
> >  	port->ddps = port_msg->ddps;
> >  	port->ldps = port_msg->legacy_device_plug_status;
> >  	port->dpcd_rev = port_msg->dpcd_revision; @@ -2295,7 +2297,7 @@
> > drm_dp_mst_handle_link_address_port(struct
> > drm_dp_mst_branch *mstb,
> >  		}
> >  	}
> >
> > -	ret = drm_dp_port_set_pdt(port, new_pdt);
> > +	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
> >  	if (ret == 1) {
> >  		send_link_addr = true;
> >  	} else if (ret < 0) {
> > @@ -2309,7 +2311,8 @@ drm_dp_mst_handle_link_address_port(struct
> > drm_dp_mst_branch *mstb,
> >  	 * we're coming out of suspend. In this case, always resend the link
> >  	 * address if there's an MSTB on this port
> >  	 */
> > -	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING)
> > +	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
> > +	    port->mcs)
> >  		send_link_addr = true;
> >
> >  	if (port->connector)
> > @@ -2346,6 +2349,7 @@ drm_dp_mst_handle_conn_stat(struct
> > drm_dp_mst_branch *mstb,
> >  	struct drm_dp_mst_port *port;
> >  	int old_ddps, old_input, ret, i;
> >  	u8 new_pdt;
> > +	bool new_mcs;
> >  	bool dowork = false, create_connector = false;
> >
> >  	port = drm_dp_get_port(mstb, conn_stat->port_number); @@ -2377,7
> > +2381,6 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> *mstb,
> >  	old_ddps = port->ddps;
> >  	old_input = port->input;
> >  	port->input = conn_stat->input_port;
> > -	port->mcs = conn_stat->message_capability_status;
> >  	port->ldps = conn_stat->legacy_device_plug_status;
> >  	port->ddps = conn_stat->displayport_device_plug_status;
> >
> > @@ -2390,8 +2393,8 @@ drm_dp_mst_handle_conn_stat(struct
> > drm_dp_mst_branch *mstb,
> >  	}
> >
> >  	new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat-
> > >peer_device_type;
> > -
> > -	ret = drm_dp_port_set_pdt(port, new_pdt);
> > +	new_mcs = conn_stat->message_capability_status;
> > +	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
> >  	if (ret == 1) {
> >  		dowork = true;
> >  	} else if (ret < 0) {
> > @@ -3958,6 +3961,8 @@ drm_dp_mst_detect_port(struct drm_connector
> > *connector,
> >  	switch (port->pdt) {
> >  	case DP_PEER_DEVICE_NONE:
> >  	case DP_PEER_DEVICE_MST_BRANCHING:
> > +		if (!port->mcs)
> > +			ret = connector_status_connected;
> >  		break;
> >
> >  	case DP_PEER_DEVICE_SST_SINK:
> > @@ -4597,7 +4602,7 @@ drm_dp_delayed_destroy_port(struct
> > drm_dp_mst_port
> > *port)
> >  	if (port->connector)
> >  		port->mgr->cbs->destroy_connector(port->mgr, port->connector);
> >
> > -	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE);
> > +	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
> >  	drm_dp_mst_put_port_malloc(port);
> >  }
> >
> --
> Cheers,
> 	Lyude Paul
--
Best regards,
Wayne Lin
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 8f54b241db08..4395d5cc0645 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1934,73 +1934,74 @@  static bool drm_dp_mst_is_dp_mst_end_device(u8 pdt, bool mcs)
 	return true;
 }
 
-static int drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt)
+static int
+drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
+		    bool new_mcs)
 {
 	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
 	struct drm_dp_mst_branch *mstb;
 	u8 rad[8], lct;
 	int ret = 0;
 
-	if (port->pdt == new_pdt)
+	if (port->pdt == new_pdt && port->mcs == new_mcs)
 		return 0;
 
 	/* Teardown the old pdt, if there is one */
-	switch (port->pdt) {
-	case DP_PEER_DEVICE_DP_LEGACY_CONV:
-	case DP_PEER_DEVICE_SST_SINK:
-		/*
-		 * If the new PDT would also have an i2c bus, don't bother
-		 * with reregistering it
-		 */
-		if (new_pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
-		    new_pdt == DP_PEER_DEVICE_SST_SINK) {
-			port->pdt = new_pdt;
-			return 0;
-		}
+	if (port->pdt != DP_PEER_DEVICE_NONE) {
+		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+			/*
+			 * If the new PDT would also have an i2c bus,
+			 * don't bother with reregistering it
+			 */
+			if (new_pdt != DP_PEER_DEVICE_NONE &&
+			    drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs)) {
+				port->pdt = new_pdt;
+				port->mcs = new_mcs;
+				return 0;
+			}
 
-		/* remove i2c over sideband */
-		drm_dp_mst_unregister_i2c_bus(&port->aux);
-		break;
-	case DP_PEER_DEVICE_MST_BRANCHING:
-		mutex_lock(&mgr->lock);
-		drm_dp_mst_topology_put_mstb(port->mstb);
-		port->mstb = NULL;
-		mutex_unlock(&mgr->lock);
-		break;
+			/* remove i2c over sideband */
+			drm_dp_mst_unregister_i2c_bus(&port->aux);
+		} else {
+			mutex_lock(&mgr->lock);
+			drm_dp_mst_topology_put_mstb(port->mstb);
+			port->mstb = NULL;
+			mutex_unlock(&mgr->lock);
+		}
 	}
 
 	port->pdt = new_pdt;
-	switch (port->pdt) {
-	case DP_PEER_DEVICE_DP_LEGACY_CONV:
-	case DP_PEER_DEVICE_SST_SINK:
-		/* add i2c over sideband */
-		ret = drm_dp_mst_register_i2c_bus(&port->aux);
-		break;
+	port->mcs = new_mcs;
 
-	case DP_PEER_DEVICE_MST_BRANCHING:
-		lct = drm_dp_calculate_rad(port, rad);
-		mstb = drm_dp_add_mst_branch_device(lct, rad);
-		if (!mstb) {
-			ret = -ENOMEM;
-			DRM_ERROR("Failed to create MSTB for port %p", port);
-			goto out;
-		}
+	if (port->pdt != DP_PEER_DEVICE_NONE) {
+		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+			/* add i2c over sideband */
+			ret = drm_dp_mst_register_i2c_bus(&port->aux);
+		} else {
+			lct = drm_dp_calculate_rad(port, rad);
+			mstb = drm_dp_add_mst_branch_device(lct, rad);
+			if (!mstb) {
+				ret = -ENOMEM;
+				DRM_ERROR("Failed to create MSTB for port %p",
+					  port);
+				goto out;
+			}
 
-		mutex_lock(&mgr->lock);
-		port->mstb = mstb;
-		mstb->mgr = port->mgr;
-		mstb->port_parent = port;
+			mutex_lock(&mgr->lock);
+			port->mstb = mstb;
+			mstb->mgr = port->mgr;
+			mstb->port_parent = port;
 
-		/*
-		 * Make sure this port's memory allocation stays
-		 * around until its child MSTB releases it
-		 */
-		drm_dp_mst_get_port_malloc(port);
-		mutex_unlock(&mgr->lock);
+			/*
+			 * Make sure this port's memory allocation stays
+			 * around until its child MSTB releases it
+			 */
+			drm_dp_mst_get_port_malloc(port);
+			mutex_unlock(&mgr->lock);
 
-		/* And make sure we send a link address for this */
-		ret = 1;
-		break;
+			/* And make sure we send a link address for this */
+			ret = 1;
+		}
 	}
 
 out:
@@ -2153,12 +2154,12 @@  drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,
 		goto error;
 	}
 
-	if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
-	     port->pdt == DP_PEER_DEVICE_SST_SINK) &&
-	    port->port_num >= DP_MST_LOGICAL_PORT_0) {
-		port->cached_edid = drm_get_edid(port->connector,
-						 &port->aux.ddc);
-		drm_connector_set_tile_property(port->connector);
+	if (port->pdt != DP_PEER_DEVICE_NONE) {
+		if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+			port->cached_edid = drm_get_edid(port->connector,
+							 &port->aux.ddc);
+			drm_connector_set_tile_property(port->connector);
+		}
 	}
 
 	mgr->cbs->register_connector(port->connector);
@@ -2223,6 +2224,7 @@  drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
 	struct drm_dp_mst_port *port;
 	int old_ddps = 0, ret;
 	u8 new_pdt = DP_PEER_DEVICE_NONE;
+	bool new_mcs = 0;
 	bool created = false, send_link_addr = false, changed = false;
 
 	port = drm_dp_get_port(mstb, port_msg->port_number);
@@ -2267,7 +2269,7 @@  drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
 	port->input = port_msg->input_port;
 	if (!port->input)
 		new_pdt = port_msg->peer_device_type;
-	port->mcs = port_msg->mcs;
+	new_mcs = port_msg->mcs;
 	port->ddps = port_msg->ddps;
 	port->ldps = port_msg->legacy_device_plug_status;
 	port->dpcd_rev = port_msg->dpcd_revision;
@@ -2295,7 +2297,7 @@  drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
 		}
 	}
 
-	ret = drm_dp_port_set_pdt(port, new_pdt);
+	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
 	if (ret == 1) {
 		send_link_addr = true;
 	} else if (ret < 0) {
@@ -2309,7 +2311,8 @@  drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
 	 * we're coming out of suspend. In this case, always resend the link
 	 * address if there's an MSTB on this port
 	 */
-	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING)
+	if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
+	    port->mcs)
 		send_link_addr = true;
 
 	if (port->connector)
@@ -2346,6 +2349,7 @@  drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb,
 	struct drm_dp_mst_port *port;
 	int old_ddps, old_input, ret, i;
 	u8 new_pdt;
+	bool new_mcs;
 	bool dowork = false, create_connector = false;
 
 	port = drm_dp_get_port(mstb, conn_stat->port_number);
@@ -2377,7 +2381,6 @@  drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb,
 	old_ddps = port->ddps;
 	old_input = port->input;
 	port->input = conn_stat->input_port;
-	port->mcs = conn_stat->message_capability_status;
 	port->ldps = conn_stat->legacy_device_plug_status;
 	port->ddps = conn_stat->displayport_device_plug_status;
 
@@ -2390,8 +2393,8 @@  drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb,
 	}
 
 	new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat->peer_device_type;
-
-	ret = drm_dp_port_set_pdt(port, new_pdt);
+	new_mcs = conn_stat->message_capability_status;
+	ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs);
 	if (ret == 1) {
 		dowork = true;
 	} else if (ret < 0) {
@@ -3958,6 +3961,8 @@  drm_dp_mst_detect_port(struct drm_connector *connector,
 	switch (port->pdt) {
 	case DP_PEER_DEVICE_NONE:
 	case DP_PEER_DEVICE_MST_BRANCHING:
+		if (!port->mcs)
+			ret = connector_status_connected;
 		break;
 
 	case DP_PEER_DEVICE_SST_SINK:
@@ -4597,7 +4602,7 @@  drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port)
 	if (port->connector)
 		port->mgr->cbs->destroy_connector(port->mgr, port->connector);
 
-	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE);
+	drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
 	drm_dp_mst_put_port_malloc(port);
 }