@@ -1935,7 +1935,7 @@ static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port,
1935
1935
return parent_lct + 1 ;
1936
1936
}
1937
1937
1938
- static bool drm_dp_mst_is_dp_mst_end_device (u8 pdt , bool mcs )
1938
+ static bool drm_dp_mst_is_end_device (u8 pdt , bool mcs )
1939
1939
{
1940
1940
switch (pdt ) {
1941
1941
case DP_PEER_DEVICE_DP_LEGACY_CONV :
@@ -1965,13 +1965,13 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
1965
1965
1966
1966
/* Teardown the old pdt, if there is one */
1967
1967
if (port -> pdt != DP_PEER_DEVICE_NONE ) {
1968
- if (drm_dp_mst_is_dp_mst_end_device (port -> pdt , port -> mcs )) {
1968
+ if (drm_dp_mst_is_end_device (port -> pdt , port -> mcs )) {
1969
1969
/*
1970
1970
* If the new PDT would also have an i2c bus,
1971
1971
* don't bother with reregistering it
1972
1972
*/
1973
1973
if (new_pdt != DP_PEER_DEVICE_NONE &&
1974
- drm_dp_mst_is_dp_mst_end_device (new_pdt , new_mcs )) {
1974
+ drm_dp_mst_is_end_device (new_pdt , new_mcs )) {
1975
1975
port -> pdt = new_pdt ;
1976
1976
port -> mcs = new_mcs ;
1977
1977
return 0 ;
@@ -1991,7 +1991,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
1991
1991
port -> mcs = new_mcs ;
1992
1992
1993
1993
if (port -> pdt != DP_PEER_DEVICE_NONE ) {
1994
- if (drm_dp_mst_is_dp_mst_end_device (port -> pdt , port -> mcs )) {
1994
+ if (drm_dp_mst_is_end_device (port -> pdt , port -> mcs )) {
1995
1995
/* add i2c over sideband */
1996
1996
ret = drm_dp_mst_register_i2c_bus (& port -> aux );
1997
1997
} else {
@@ -2172,7 +2172,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,
2172
2172
}
2173
2173
2174
2174
if (port -> pdt != DP_PEER_DEVICE_NONE &&
2175
- drm_dp_mst_is_dp_mst_end_device (port -> pdt , port -> mcs )) {
2175
+ drm_dp_mst_is_end_device (port -> pdt , port -> mcs )) {
2176
2176
port -> cached_edid = drm_get_edid (port -> connector ,
2177
2177
& port -> aux .ddc );
2178
2178
drm_connector_set_tile_property (port -> connector );
@@ -2302,14 +2302,18 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
2302
2302
mutex_unlock (& mgr -> lock );
2303
2303
}
2304
2304
2305
- if (old_ddps != port -> ddps ) {
2306
- if (port -> ddps ) {
2307
- if (!port -> input ) {
2308
- drm_dp_send_enum_path_resources (mgr , mstb ,
2309
- port );
2310
- }
2305
+ /*
2306
+ * Reprobe PBN caps on both hotplug, and when re-probing the link
2307
+ * for our parent mstb
2308
+ */
2309
+ if (old_ddps != port -> ddps || !created ) {
2310
+ if (port -> ddps && !port -> input ) {
2311
+ ret = drm_dp_send_enum_path_resources (mgr , mstb ,
2312
+ port );
2313
+ if (ret == 1 )
2314
+ changed = true;
2311
2315
} else {
2312
- port -> available_pbn = 0 ;
2316
+ port -> full_pbn = 0 ;
2313
2317
}
2314
2318
}
2315
2319
@@ -2401,11 +2405,10 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb,
2401
2405
port -> ddps = conn_stat -> displayport_device_plug_status ;
2402
2406
2403
2407
if (old_ddps != port -> ddps ) {
2404
- if (port -> ddps ) {
2405
- dowork = true;
2406
- } else {
2407
- port -> available_pbn = 0 ;
2408
- }
2408
+ if (port -> ddps && !port -> input )
2409
+ drm_dp_send_enum_path_resources (mgr , mstb , port );
2410
+ else
2411
+ port -> full_pbn = 0 ;
2409
2412
}
2410
2413
2411
2414
new_pdt = port -> input ? DP_PEER_DEVICE_NONE : conn_stat -> peer_device_type ;
@@ -2556,13 +2559,6 @@ static int drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mg
2556
2559
if (port -> input || !port -> ddps )
2557
2560
continue ;
2558
2561
2559
- if (!port -> available_pbn ) {
2560
- drm_modeset_lock (& mgr -> base .lock , NULL );
2561
- drm_dp_send_enum_path_resources (mgr , mstb , port );
2562
- drm_modeset_unlock (& mgr -> base .lock );
2563
- changed = true;
2564
- }
2565
-
2566
2562
if (port -> mstb )
2567
2563
mstb_child = drm_dp_mst_topology_get_mstb_validated (
2568
2564
mgr , port -> mstb );
@@ -2990,6 +2986,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
2990
2986
2991
2987
ret = drm_dp_mst_wait_tx_reply (mstb , txmsg );
2992
2988
if (ret > 0 ) {
2989
+ ret = 0 ;
2993
2990
path_res = & txmsg -> reply .u .path_resources ;
2994
2991
2995
2992
if (txmsg -> reply .reply_type == DP_SIDEBAND_REPLY_NAK ) {
@@ -3002,14 +2999,22 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
3002
2999
path_res -> port_number ,
3003
3000
path_res -> full_payload_bw_number ,
3004
3001
path_res -> avail_payload_bw_number );
3005
- port -> available_pbn =
3006
- path_res -> avail_payload_bw_number ;
3002
+
3003
+ /*
3004
+ * If something changed, make sure we send a
3005
+ * hotplug
3006
+ */
3007
+ if (port -> full_pbn != path_res -> full_payload_bw_number ||
3008
+ port -> fec_capable != path_res -> fec_capable )
3009
+ ret = 1 ;
3010
+
3011
+ port -> full_pbn = path_res -> full_payload_bw_number ;
3007
3012
port -> fec_capable = path_res -> fec_capable ;
3008
3013
}
3009
3014
}
3010
3015
3011
3016
kfree (txmsg );
3012
- return 0 ;
3017
+ return ret ;
3013
3018
}
3014
3019
3015
3020
static struct drm_dp_mst_port * drm_dp_get_last_connected_port_to_mstb (struct drm_dp_mst_branch * mstb )
@@ -3596,13 +3601,9 @@ drm_dp_mst_topology_mgr_invalidate_mstb(struct drm_dp_mst_branch *mstb)
3596
3601
/* The link address will need to be re-sent on resume */
3597
3602
mstb -> link_address_sent = false;
3598
3603
3599
- list_for_each_entry (port , & mstb -> ports , next ) {
3600
- /* The PBN for each port will also need to be re-probed */
3601
- port -> available_pbn = 0 ;
3602
-
3604
+ list_for_each_entry (port , & mstb -> ports , next )
3603
3605
if (port -> mstb )
3604
3606
drm_dp_mst_topology_mgr_invalidate_mstb (port -> mstb );
3605
- }
3606
3607
}
3607
3608
3608
3609
/**
@@ -4829,41 +4830,102 @@ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port,
4829
4830
return false;
4830
4831
}
4831
4832
4832
- static inline
4833
- int drm_dp_mst_atomic_check_bw_limit (struct drm_dp_mst_branch * branch ,
4834
- struct drm_dp_mst_topology_state * mst_state )
4833
+ static int
4834
+ drm_dp_mst_atomic_check_port_bw_limit (struct drm_dp_mst_port * port ,
4835
+ struct drm_dp_mst_topology_state * state );
4836
+
4837
+ static int
4838
+ drm_dp_mst_atomic_check_mstb_bw_limit (struct drm_dp_mst_branch * mstb ,
4839
+ struct drm_dp_mst_topology_state * state )
4835
4840
{
4836
- struct drm_dp_mst_port * port ;
4837
4841
struct drm_dp_vcpi_allocation * vcpi ;
4838
- int pbn_limit = 0 , pbn_used = 0 ;
4842
+ struct drm_dp_mst_port * port ;
4843
+ int pbn_used = 0 , ret ;
4844
+ bool found = false;
4839
4845
4840
- list_for_each_entry (port , & branch -> ports , next ) {
4841
- if (port -> mstb )
4842
- if (drm_dp_mst_atomic_check_bw_limit (port -> mstb , mst_state ))
4843
- return - ENOSPC ;
4846
+ /* Check that we have at least one port in our state that's downstream
4847
+ * of this branch, otherwise we can skip this branch
4848
+ */
4849
+ list_for_each_entry (vcpi , & state -> vcpis , next ) {
4850
+ if (!vcpi -> pbn ||
4851
+ !drm_dp_mst_port_downstream_of_branch (vcpi -> port , mstb ))
4852
+ continue ;
4844
4853
4845
- if ( port -> available_pbn > 0 )
4846
- pbn_limit = port -> available_pbn ;
4854
+ found = true;
4855
+ break ;
4847
4856
}
4848
- DRM_DEBUG_ATOMIC ( "[MST BRANCH:%p] branch has %d PBN available\n" ,
4849
- branch , pbn_limit ) ;
4857
+ if (! found )
4858
+ return 0 ;
4850
4859
4851
- list_for_each_entry (vcpi , & mst_state -> vcpis , next ) {
4852
- if (!vcpi -> pbn )
4853
- continue ;
4860
+ if (mstb -> port_parent )
4861
+ DRM_DEBUG_ATOMIC ("[MSTB:%p] [MST PORT:%p] Checking bandwidth limits on [MSTB:%p]\n" ,
4862
+ mstb -> port_parent -> parent , mstb -> port_parent ,
4863
+ mstb );
4864
+ else
4865
+ DRM_DEBUG_ATOMIC ("[MSTB:%p] Checking bandwidth limits\n" ,
4866
+ mstb );
4867
+
4868
+ list_for_each_entry (port , & mstb -> ports , next ) {
4869
+ ret = drm_dp_mst_atomic_check_port_bw_limit (port , state );
4870
+ if (ret < 0 )
4871
+ return ret ;
4854
4872
4855
- if (drm_dp_mst_port_downstream_of_branch (vcpi -> port , branch ))
4856
- pbn_used += vcpi -> pbn ;
4873
+ pbn_used += ret ;
4857
4874
}
4858
- DRM_DEBUG_ATOMIC ("[MST BRANCH:%p] branch used %d PBN\n" ,
4859
- branch , pbn_used );
4860
4875
4861
- if (pbn_used > pbn_limit ) {
4862
- DRM_DEBUG_ATOMIC ("[MST BRANCH:%p] No available bandwidth\n" ,
4863
- branch );
4876
+ return pbn_used ;
4877
+ }
4878
+
4879
+ static int
4880
+ drm_dp_mst_atomic_check_port_bw_limit (struct drm_dp_mst_port * port ,
4881
+ struct drm_dp_mst_topology_state * state )
4882
+ {
4883
+ struct drm_dp_vcpi_allocation * vcpi ;
4884
+ int pbn_used = 0 ;
4885
+
4886
+ if (port -> pdt == DP_PEER_DEVICE_NONE )
4887
+ return 0 ;
4888
+
4889
+ if (drm_dp_mst_is_end_device (port -> pdt , port -> mcs )) {
4890
+ bool found = false;
4891
+
4892
+ list_for_each_entry (vcpi , & state -> vcpis , next ) {
4893
+ if (vcpi -> port != port )
4894
+ continue ;
4895
+ if (!vcpi -> pbn )
4896
+ return 0 ;
4897
+
4898
+ found = true;
4899
+ break ;
4900
+ }
4901
+ if (!found )
4902
+ return 0 ;
4903
+
4904
+ /* This should never happen, as it means we tried to
4905
+ * set a mode before querying the full_pbn
4906
+ */
4907
+ if (WARN_ON (!port -> full_pbn ))
4908
+ return - EINVAL ;
4909
+
4910
+ pbn_used = vcpi -> pbn ;
4911
+ } else {
4912
+ pbn_used = drm_dp_mst_atomic_check_mstb_bw_limit (port -> mstb ,
4913
+ state );
4914
+ if (pbn_used <= 0 )
4915
+ return pbn_used ;
4916
+ }
4917
+
4918
+ if (pbn_used > port -> full_pbn ) {
4919
+ DRM_DEBUG_ATOMIC ("[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n" ,
4920
+ port -> parent , port , pbn_used ,
4921
+ port -> full_pbn );
4864
4922
return - ENOSPC ;
4865
4923
}
4866
- return 0 ;
4924
+
4925
+ DRM_DEBUG_ATOMIC ("[MSTB:%p] [MST PORT:%p] uses %d out of %d PBN\n" ,
4926
+ port -> parent , port , pbn_used , port -> full_pbn );
4927
+
4928
+ return pbn_used ;
4867
4929
}
4868
4930
4869
4931
static inline int
@@ -5061,9 +5123,15 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
5061
5123
ret = drm_dp_mst_atomic_check_vcpi_alloc_limit (mgr , mst_state );
5062
5124
if (ret )
5063
5125
break ;
5064
- ret = drm_dp_mst_atomic_check_bw_limit (mgr -> mst_primary , mst_state );
5065
- if (ret )
5126
+
5127
+ mutex_lock (& mgr -> lock );
5128
+ ret = drm_dp_mst_atomic_check_mstb_bw_limit (mgr -> mst_primary ,
5129
+ mst_state );
5130
+ mutex_unlock (& mgr -> lock );
5131
+ if (ret < 0 )
5066
5132
break ;
5133
+ else
5134
+ ret = 0 ;
5067
5135
}
5068
5136
5069
5137
return ret ;
0 commit comments