@@ -4125,7 +4125,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
41254125{
41264126 struct drm_dp_mst_topology_state * topology_state ;
41274127 struct drm_dp_vcpi_allocation * pos , * vcpi = NULL ;
4128- int prev_slots , req_slots ;
4128+ int prev_slots , prev_bw , req_slots ;
41294129
41304130 topology_state = drm_atomic_get_mst_topology_state (state , mgr );
41314131 if (IS_ERR (topology_state ))
@@ -4136,6 +4136,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
41364136 if (pos -> port == port ) {
41374137 vcpi = pos ;
41384138 prev_slots = vcpi -> vcpi ;
4139+ prev_bw = vcpi -> pbn ;
41394140
41404141 /*
41414142 * This should never happen, unless the driver tries
@@ -4151,8 +4152,10 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
41514152 break ;
41524153 }
41534154 }
4154- if (!vcpi )
4155+ if (!vcpi ) {
41554156 prev_slots = 0 ;
4157+ prev_bw = 0 ;
4158+ }
41564159
41574160 if (pbn_div <= 0 )
41584161 pbn_div = mgr -> pbn_div ;
@@ -4162,6 +4165,9 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
41624165 DRM_DEBUG_ATOMIC ("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n" ,
41634166 port -> connector -> base .id , port -> connector -> name ,
41644167 port , prev_slots , req_slots );
4168+ DRM_DEBUG_ATOMIC ("[CONNECTOR:%d:%s] [MST PORT:%p] PBN %d -> %d\n" ,
4169+ port -> connector -> base .id , port -> connector -> name ,
4170+ port , prev_bw , pbn );
41654171
41664172 /* Add the new allocation to the state */
41674173 if (!vcpi ) {
@@ -4174,6 +4180,7 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
41744180 list_add (& vcpi -> next , & topology_state -> vcpis );
41754181 }
41764182 vcpi -> vcpi = req_slots ;
4183+ vcpi -> pbn = pbn ;
41774184
41784185 return req_slots ;
41794186}
@@ -4750,6 +4757,58 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
47504757 kfree (mst_state );
47514758}
47524759
4760+ static bool drm_dp_mst_port_downstream_of_branch (struct drm_dp_mst_port * port ,
4761+ struct drm_dp_mst_branch * branch )
4762+ {
4763+ while (port -> parent ) {
4764+ if (port -> parent == branch )
4765+ return true;
4766+
4767+ if (port -> parent -> port_parent )
4768+ port = port -> parent -> port_parent ;
4769+ else
4770+ break ;
4771+ }
4772+ return false;
4773+ }
4774+
4775+ static inline
4776+ int drm_dp_mst_atomic_check_bw_limit (struct drm_dp_mst_branch * branch ,
4777+ struct drm_dp_mst_topology_state * mst_state )
4778+ {
4779+ struct drm_dp_mst_port * port ;
4780+ struct drm_dp_vcpi_allocation * vcpi ;
4781+ int pbn_limit = 0 , pbn_used = 0 ;
4782+
4783+ list_for_each_entry (port , & branch -> ports , next ) {
4784+ if (port -> mstb )
4785+ if (drm_dp_mst_atomic_check_bw_limit (port -> mstb , mst_state ))
4786+ return - ENOSPC ;
4787+
4788+ if (port -> available_pbn > 0 )
4789+ pbn_limit = port -> available_pbn ;
4790+ }
4791+ DRM_DEBUG_ATOMIC ("[MST BRANCH:%p] branch has %d PBN available\n" ,
4792+ branch , pbn_limit );
4793+
4794+ list_for_each_entry (vcpi , & mst_state -> vcpis , next ) {
4795+ if (!vcpi -> pbn )
4796+ continue ;
4797+
4798+ if (drm_dp_mst_port_downstream_of_branch (vcpi -> port , branch ))
4799+ pbn_used += vcpi -> pbn ;
4800+ }
4801+ DRM_DEBUG_ATOMIC ("[MST BRANCH:%p] branch used %d PBN\n" ,
4802+ branch , pbn_used );
4803+
4804+ if (pbn_used > pbn_limit ) {
4805+ DRM_DEBUG_ATOMIC ("[MST BRANCH:%p] No available bandwidth\n" ,
4806+ branch );
4807+ return - ENOSPC ;
4808+ }
4809+ return 0 ;
4810+ }
4811+
47534812static inline int
47544813drm_dp_mst_atomic_check_topology_state (struct drm_dp_mst_topology_mgr * mgr ,
47554814 struct drm_dp_mst_topology_state * mst_state )
@@ -4881,6 +4940,9 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
48814940 ret = drm_dp_mst_atomic_check_topology_state (mgr , mst_state );
48824941 if (ret )
48834942 break ;
4943+ ret = drm_dp_mst_atomic_check_bw_limit (mgr -> mst_primary , mst_state );
4944+ if (ret )
4945+ break ;
48844946 }
48854947
48864948 return ret ;
0 commit comments