[3/3] drm/dp/mst: Track available time slots in DP Multi-Stream Transport Packet
diff mbox

Message ID 1479434628-2373-4-git-send-email-dhinakaran.pandiyan@intel.com
State New
Headers show

Commit Message

Dhinakaran Pandiyan Nov. 18, 2016, 2:03 a.m. UTC
The avail_slots member in struct drm_dp_mst_topology_mgr does not really
track the available time slots in a MTP(Multi-Stream Transport Packet). It
is assigned an initial value when the topology manager is setup but not
updated after that.

So, let's use avail_slots to store the number of unallocated slots out of
the total 64. The value will be updated when vcpi allocation or reset
happens. Since vcpi allocation and deallocation can happen simultaneously,
the struct drm_dp_mst_topology_mgr.lock mutex is used to protect
it from concurrent accesses.

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 55 ++++++++++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_dp_mst.c   |  5 +++-
 include/drm/drm_dp_mst_helper.h       |  2 +-
 3 files changed, 47 insertions(+), 15 deletions(-)

Comments

kernel test robot Nov. 18, 2016, 5:53 a.m. UTC | #1
Hi Dhinakaran,

[auto build test WARNING on drm/drm-next]
[also build test WARNING on v4.9-rc5 next-20161117]
[cannot apply to drm-intel/for-linux-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dhinakaran-Pandiyan/Track-available-link-bandwidth-for-DP-MST/20161118-101200
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
reproduce: make htmldocs; make DOCBOOKS='' pdfdocs

All warnings (new ones prefixed by >>):

   make[3]: warning: jobserver unavailable: using -j1.  Add '+' to parent make rule.
   include/linux/init.h:1: warning: no structured comments found
   include/linux/workqueue.h:392: warning: No description found for parameter '...'
   include/linux/workqueue.h:392: warning: Excess function parameter 'args' description in 'alloc_workqueue'
   include/linux/workqueue.h:413: warning: No description found for parameter '...'
   include/linux/workqueue.h:413: warning: Excess function parameter 'args' description in 'alloc_ordered_workqueue'
   include/linux/kthread.h:26: warning: No description found for parameter '...'
   kernel/sys.c:1: warning: no structured comments found
   drivers/dma-buf/seqno-fence.c:1: warning: no structured comments found
   include/sound/core.h:324: warning: No description found for parameter '...'
   include/sound/core.h:335: warning: No description found for parameter '...'
   include/sound/core.h:388: warning: No description found for parameter '...'
   include/drm/drm_drv.h:295: warning: Incorrect use of kernel-doc format: 	 * Hook for allocating the GEM object struct, for use by core
   include/drm/drm_drv.h:407: warning: No description found for parameter 'load'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'firstopen'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'open'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'preclose'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'postclose'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'lastclose'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'unload'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'dma_ioctl'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'dma_quiescent'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'context_dtor'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'set_busid'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'irq_handler'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'irq_preinstall'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'irq_postinstall'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'irq_uninstall'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'debugfs_init'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'debugfs_cleanup'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_open_object'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_close_object'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_create_object'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'prime_handle_to_fd'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'prime_fd_to_handle'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_export'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_import'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_pin'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_unpin'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_res_obj'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_get_sg_table'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_import_sg_table'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_vmap'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_vunmap'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_prime_mmap'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'vgaarb_irq'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'gem_vm_ops'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'major'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'minor'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'patchlevel'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'name'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'desc'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'date'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'driver_features'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'dev_priv_size'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'ioctls'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'num_ioctls'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'fops'
   include/drm/drm_drv.h:407: warning: No description found for parameter 'legacy_dev_list'
>> drivers/gpu/drm/drm_dp_mst_topology.c:2474: warning: No description found for parameter 'port'
   drivers/gpu/drm/drm_dp_mst_topology.c:2475: warning: No description found for parameter 'port'
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_fence_reg.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_fence_reg.c
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -internal drivers/gpu/drm/i915/i915_gem_fence_reg.c' failed with return code 2
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_fence_reg.c
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function fence register handling drivers/gpu/drm/i915/i915_gem_fence_reg.c' failed with return code 1
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_fence_reg.c
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function tiling swizzling details drivers/gpu/drm/i915/i915_gem_fence_reg.c' failed with return code 1
   include/media/media-entity.h:1054: warning: No description found for parameter '...'
   include/net/mac80211.h:3207: ERROR: Unexpected indentation.
   include/net/mac80211.h:3210: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/net/mac80211.h:3212: ERROR: Unexpected indentation.
   include/net/mac80211.h:3213: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/net/mac80211.h:1772: ERROR: Unexpected indentation.
   include/net/mac80211.h:1776: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/sched/fair.c:7259: WARNING: Inline emphasis start-string without end-string.
   kernel/time/timer.c:1240: ERROR: Unexpected indentation.
   kernel/time/timer.c:1242: ERROR: Unexpected indentation.
   kernel/time/timer.c:1243: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:121: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:124: ERROR: Unexpected indentation.
   include/linux/wait.h:126: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/time/hrtimer.c:1021: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/signal.c:317: WARNING: Inline literal start-string without end-string.
   drivers/base/firmware_class.c:1348: WARNING: Bullet list ends without a blank line; unexpected unindent.
   drivers/message/fusion/mptbase.c:5054: WARNING: Definition list ends without a blank line; unexpected unindent.
   drivers/tty/serial/serial_core.c:1893: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/spi/spi.h:369: ERROR: Unexpected indentation.
   WARNING: dvipng command 'dvipng' cannot be run (needed for math display), check the imgmath_dvipng setting

vim +/port +2474 drivers/gpu/drm/drm_dp_mst_topology.c

8ae22cb4 Dave Airlie         2016-02-17  2458  		edid = drm_get_edid(connector, &port->aux.ddc);
8ae22cb4 Dave Airlie         2016-02-17  2459  		drm_mode_connector_set_tile_property(connector);
8ae22cb4 Dave Airlie         2016-02-17  2460  	}
ef8f9bea Libin Yang          2015-12-02  2461  	port->has_audio = drm_detect_monitor_audio(edid);
ad7f8a1f Dave Airlie         2014-06-05  2462  	drm_dp_put_port(port);
ad7f8a1f Dave Airlie         2014-06-05  2463  	return edid;
ad7f8a1f Dave Airlie         2014-06-05  2464  }
ad7f8a1f Dave Airlie         2014-06-05  2465  EXPORT_SYMBOL(drm_dp_mst_get_edid);
ad7f8a1f Dave Airlie         2014-06-05  2466  
ad7f8a1f Dave Airlie         2014-06-05  2467  /**
ad7f8a1f Dave Airlie         2014-06-05  2468   * drm_dp_find_vcpi_slots() - find slots for this PBN value
ad7f8a1f Dave Airlie         2014-06-05  2469   * @mgr: manager to use
ad7f8a1f Dave Airlie         2014-06-05  2470   * @pbn: payload bandwidth to convert into slots.
ad7f8a1f Dave Airlie         2014-06-05  2471   */
ad7f8a1f Dave Airlie         2014-06-05  2472  int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2473  			   struct drm_dp_mst_port *port, int pbn)
ad7f8a1f Dave Airlie         2014-06-05 @2474  {
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2475  	int req_slots, curr_slots, new_slots, ret;
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2476  
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2477  	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2478  	curr_slots = drm_dp_mst_get_vcpi_slots(mgr, port);
ad7f8a1f Dave Airlie         2014-06-05  2479  
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2480  	if (req_slots <= curr_slots)
af2a61e3 Dhinakaran Pandiyan 2016-11-17  2481  		return req_slots;
ad7f8a1f Dave Airlie         2014-06-05  2482  

:::::: The code at line 2474 was first introduced by commit
:::::: ad7f8a1f9ced7f049f9b66d588723f243a7034cd drm/helper: add Displayport multi-stream helper (v0.6)

:::::: TO: Dave Airlie <airlied@redhat.com>
:::::: CC: Dave Airlie <airlied@redhat.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Manasi Navare Nov. 18, 2016, 6:19 a.m. UTC | #2
On Thu, Nov 17, 2016 at 06:03:48PM -0800, Dhinakaran Pandiyan wrote:
> The avail_slots member in struct drm_dp_mst_topology_mgr does not really
> track the available time slots in a MTP(Multi-Stream Transport Packet). It
> is assigned an initial value when the topology manager is setup but not
> updated after that.
> 
> So, let's use avail_slots to store the number of unallocated slots out of
> the total 64. The value will be updated when vcpi allocation or reset
> happens. Since vcpi allocation and deallocation can happen simultaneously,
> the struct drm_dp_mst_topology_mgr.lock mutex is used to protect
> it from concurrent accesses.
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> ---
>  drivers/gpu/drm/drm_dp_mst_topology.c | 55 ++++++++++++++++++++++++++---------
>  drivers/gpu/drm/i915/intel_dp_mst.c   |  5 +++-
>  include/drm/drm_dp_mst_helper.h       |  2 +-
>  3 files changed, 47 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
> index 26dfd99..19e2250 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -2040,7 +2040,9 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
>  		}
>  		mgr->total_pbn = 64 * mgr->pbn_div;
>  		mgr->total_slots = 64;
> -		mgr->avail_slots = mgr->total_slots;
> +
> +		/* 1 slot out of the 64 time slots is used for MTP header */
> +		mgr->avail_slots = mgr->total_slots - 1;
>  
>  		/* add initial branch device at LCT 1 */
>  		mstb = drm_dp_add_mst_branch_device(1, NULL);
> @@ -2465,34 +2467,52 @@ EXPORT_SYMBOL(drm_dp_mst_get_edid);
>   * @pbn: payload bandwidth to convert into slots.
>   */
>  int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
> -			   int pbn)
> +			   struct drm_dp_mst_port *port, int pbn)
>  {
> -	int num_slots;
> +	int req_slots, curr_slots, new_slots, ret;
> +
> +	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> +	curr_slots = drm_dp_mst_get_vcpi_slots(mgr, port);
>  
> -	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> +	if (req_slots <= curr_slots)
> +		return req_slots;

Are you sure you want to return from the function at this
or should this just be ret = req_slots as you are returning ret at the end of the function.

Manasi
>  
> -	if (num_slots > mgr->avail_slots)
> -		return -ENOSPC;
> -	return num_slots;
> +	new_slots = req_slots - curr_slots;
> +	mutex_lock(&mgr->lock);
> +	if (new_slots <= mgr->avail_slots) {
> +		ret = req_slots;
> +	} else {
> +		DRM_DEBUG_KMS("not enough vcpi slots, req=%d avail=%d\n", req_slots, mgr->avail_slots);
> +		ret =  -ENOSPC;
> +	}
> +	mutex_unlock(&mgr->lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(drm_dp_find_vcpi_slots);
>  
>  static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,
>  			    struct drm_dp_vcpi *vcpi, int pbn)
>  {
> -	int num_slots;
> +	int req_slots;
>  	int ret;
>  
> -	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> +	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
>  
> -	if (num_slots > mgr->avail_slots)
> -		return -ENOSPC;
> +	mutex_lock(&mgr->lock);
> +	if (req_slots > mgr->avail_slots) {
> +		ret = -ENOSPC;
> +		goto out;
> +	}
>  
>  	vcpi->pbn = pbn;
> -	vcpi->aligned_pbn = num_slots * mgr->pbn_div;
> -	vcpi->num_slots = num_slots;
> +	vcpi->aligned_pbn = req_slots * mgr->pbn_div;
> +	vcpi->num_slots = req_slots;
>  
>  	ret = drm_dp_mst_assign_payload_id(mgr, vcpi);
> +
> +out:
> +	mutex_unlock(&mgr->lock);
>  	if (ret < 0)
>  		return ret;
>  	return 0;
> @@ -2530,6 +2550,10 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp
>  	DRM_DEBUG_KMS("initing vcpi for %d %d\n", pbn, port->vcpi.num_slots);
>  	*slots = port->vcpi.num_slots;
>  
> +	mutex_lock(&mgr->lock);
> +	mgr->avail_slots -= port->vcpi.num_slots;
> +	mutex_unlock(&mgr->lock);
> +
>  	drm_dp_put_port(port);
>  	return true;
>  out:
> @@ -2562,6 +2586,11 @@ void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm
>  	port = drm_dp_get_validated_port_ref(mgr, port);
>  	if (!port)
>  		return;
> +
> +	mutex_lock(&mgr->lock);
> +	mgr->avail_slots += port->vcpi.num_slots;
> +	mutex_unlock(&mgr->lock);
> +
>  	port->vcpi.num_slots = 0;
>  	drm_dp_put_port(port);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 4280a83..bad9300 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -42,6 +42,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  	int lane_count, slots;
>  	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
>  	int mst_pbn;
> +	struct intel_connector *connector =
> +		to_intel_connector(conn_state->connector);
>  
>  	pipe_config->dp_encoder_is_mst = true;
>  	pipe_config->has_pch_encoder = false;
> @@ -62,7 +64,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  	mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
>  
>  	pipe_config->pbn = mst_pbn;
> -	slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
> +	slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, connector->port,
> +				       mst_pbn);
>  	if (slots < 0) {
>  		DRM_ERROR("not enough available time slots for pbn=%d", mst_pbn);
>  		return false;
> diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
> index 0032076..5c55528 100644
> --- a/include/drm/drm_dp_mst_helper.h
> +++ b/include/drm/drm_dp_mst_helper.h
> @@ -590,7 +590,7 @@ void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
>  
>  
>  int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
> -			   int pbn);
> +			   struct drm_dp_mst_port *port, int pbn);
>  
>  
>  int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr);
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Chris Wilson Nov. 18, 2016, 6:57 a.m. UTC | #3
On Thu, Nov 17, 2016 at 06:03:48PM -0800, Dhinakaran Pandiyan wrote:
>  static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,
>  			    struct drm_dp_vcpi *vcpi, int pbn)
>  {
> -	int num_slots;
> +	int req_slots;
>  	int ret;
>  
> -	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> +	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
>  
> -	if (num_slots > mgr->avail_slots)
> -		return -ENOSPC;
> +	mutex_lock(&mgr->lock);
> +	if (req_slots > mgr->avail_slots) {
> +		ret = -ENOSPC;
> +		goto out;
> +	}

You are not atomically reducing the mgr->avail_slots, leading to
possible overallocation of multiple streams?
-Chris
Daniel Vetter Nov. 18, 2016, 8:44 a.m. UTC | #4
On Fri, Nov 18, 2016 at 06:57:01AM +0000, Chris Wilson wrote:
> On Thu, Nov 17, 2016 at 06:03:48PM -0800, Dhinakaran Pandiyan wrote:
> >  static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,
> >  			    struct drm_dp_vcpi *vcpi, int pbn)
> >  {
> > -	int num_slots;
> > +	int req_slots;
> >  	int ret;
> >  
> > -	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> > +	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
> >  
> > -	if (num_slots > mgr->avail_slots)
> > -		return -ENOSPC;
> > +	mutex_lock(&mgr->lock);
> > +	if (req_slots > mgr->avail_slots) {
> > +		ret = -ENOSPC;
> > +		goto out;
> > +	}
> 
> You are not atomically reducing the mgr->avail_slots, leading to
> possible overallocation of multiple streams?

Yup, see my lenghty reply to patch 1 for what needs to be done here to fix
this correctly.
-Daniel
Dhinakaran Pandiyan Nov. 19, 2016, 12:07 a.m. UTC | #5
On Fri, 2016-11-18 at 06:57 +0000, Chris Wilson wrote:
> On Thu, Nov 17, 2016 at 06:03:48PM -0800, Dhinakaran Pandiyan wrote:

> >  static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,

> >  			    struct drm_dp_vcpi *vcpi, int pbn)

> >  {

> > -	int num_slots;

> > +	int req_slots;

> >  	int ret;

> >  

> > -	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);

> > +	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);

> >  

> > -	if (num_slots > mgr->avail_slots)

> > -		return -ENOSPC;

> > +	mutex_lock(&mgr->lock);

> > +	if (req_slots > mgr->avail_slots) {

> > +		ret = -ENOSPC;

> > +		goto out;

> > +	}

> 

> You are not atomically reducing the mgr->avail_slots, leading to

> possible overallocation of multiple streams?

> -Chris

> 


Yeah, I got it wrong. I should have reduced mgr->avail_slots here before
releasing the mutex. Thanks for pointing it out.

Patch
diff mbox

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 26dfd99..19e2250 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -2040,7 +2040,9 @@  int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
 		}
 		mgr->total_pbn = 64 * mgr->pbn_div;
 		mgr->total_slots = 64;
-		mgr->avail_slots = mgr->total_slots;
+
+		/* 1 slot out of the 64 time slots is used for MTP header */
+		mgr->avail_slots = mgr->total_slots - 1;
 
 		/* add initial branch device at LCT 1 */
 		mstb = drm_dp_add_mst_branch_device(1, NULL);
@@ -2465,34 +2467,52 @@  EXPORT_SYMBOL(drm_dp_mst_get_edid);
  * @pbn: payload bandwidth to convert into slots.
  */
 int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
-			   int pbn)
+			   struct drm_dp_mst_port *port, int pbn)
 {
-	int num_slots;
+	int req_slots, curr_slots, new_slots, ret;
+
+	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
+	curr_slots = drm_dp_mst_get_vcpi_slots(mgr, port);
 
-	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
+	if (req_slots <= curr_slots)
+		return req_slots;
 
-	if (num_slots > mgr->avail_slots)
-		return -ENOSPC;
-	return num_slots;
+	new_slots = req_slots - curr_slots;
+	mutex_lock(&mgr->lock);
+	if (new_slots <= mgr->avail_slots) {
+		ret = req_slots;
+	} else {
+		DRM_DEBUG_KMS("not enough vcpi slots, req=%d avail=%d\n", req_slots, mgr->avail_slots);
+		ret =  -ENOSPC;
+	}
+	mutex_unlock(&mgr->lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_dp_find_vcpi_slots);
 
 static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,
 			    struct drm_dp_vcpi *vcpi, int pbn)
 {
-	int num_slots;
+	int req_slots;
 	int ret;
 
-	num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
+	req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
 
-	if (num_slots > mgr->avail_slots)
-		return -ENOSPC;
+	mutex_lock(&mgr->lock);
+	if (req_slots > mgr->avail_slots) {
+		ret = -ENOSPC;
+		goto out;
+	}
 
 	vcpi->pbn = pbn;
-	vcpi->aligned_pbn = num_slots * mgr->pbn_div;
-	vcpi->num_slots = num_slots;
+	vcpi->aligned_pbn = req_slots * mgr->pbn_div;
+	vcpi->num_slots = req_slots;
 
 	ret = drm_dp_mst_assign_payload_id(mgr, vcpi);
+
+out:
+	mutex_unlock(&mgr->lock);
 	if (ret < 0)
 		return ret;
 	return 0;
@@ -2530,6 +2550,10 @@  bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp
 	DRM_DEBUG_KMS("initing vcpi for %d %d\n", pbn, port->vcpi.num_slots);
 	*slots = port->vcpi.num_slots;
 
+	mutex_lock(&mgr->lock);
+	mgr->avail_slots -= port->vcpi.num_slots;
+	mutex_unlock(&mgr->lock);
+
 	drm_dp_put_port(port);
 	return true;
 out:
@@ -2562,6 +2586,11 @@  void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm
 	port = drm_dp_get_validated_port_ref(mgr, port);
 	if (!port)
 		return;
+
+	mutex_lock(&mgr->lock);
+	mgr->avail_slots += port->vcpi.num_slots;
+	mutex_unlock(&mgr->lock);
+
 	port->vcpi.num_slots = 0;
 	drm_dp_put_port(port);
 }
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 4280a83..bad9300 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -42,6 +42,8 @@  static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 	int lane_count, slots;
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	int mst_pbn;
+	struct intel_connector *connector =
+		to_intel_connector(conn_state->connector);
 
 	pipe_config->dp_encoder_is_mst = true;
 	pipe_config->has_pch_encoder = false;
@@ -62,7 +64,8 @@  static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 	mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
 
 	pipe_config->pbn = mst_pbn;
-	slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
+	slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, connector->port,
+				       mst_pbn);
 	if (slots < 0) {
 		DRM_ERROR("not enough available time slots for pbn=%d", mst_pbn);
 		return false;
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 0032076..5c55528 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -590,7 +590,7 @@  void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
 
 
 int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
-			   int pbn);
+			   struct drm_dp_mst_port *port, int pbn);
 
 
 int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr);