diff options
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 247 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp_mst.c | 54 | ||||
-rw-r--r-- | include/drm/drm_dp_mst_helper.h | 23 |
4 files changed, 266 insertions, 62 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index e3497bc49494..88db6d7e1a36 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -3011,21 +3011,42 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, | |||
3011 | } | 3011 | } |
3012 | 3012 | ||
3013 | /** | 3013 | /** |
3014 | * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state | 3014 | * drm_dp_atomic_find_vcpi_slots() - Find and add VCPI slots to the state |
3015 | * @state: global atomic state | 3015 | * @state: global atomic state |
3016 | * @mgr: MST topology manager for the port | 3016 | * @mgr: MST topology manager for the port |
3017 | * @port: port to find vcpi slots for | 3017 | * @port: port to find vcpi slots for |
3018 | * @pbn: bandwidth required for the mode in PBN | 3018 | * @pbn: bandwidth required for the mode in PBN |
3019 | * | 3019 | * |
3020 | * RETURNS: | 3020 | * Allocates VCPI slots to @port, replacing any previous VCPI allocations it |
3021 | * Total slots in the atomic state assigned for this port or error | 3021 | * may have had. Any atomic drivers which support MST must call this function |
3022 | * in their &drm_encoder_helper_funcs.atomic_check() callback to change the | ||
3023 | * current VCPI allocation for the new state, but only when | ||
3024 | * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set | ||
3025 | * to ensure compatibility with userspace applications that still use the | ||
3026 | * legacy modesetting UAPI. | ||
3027 | * | ||
3028 | * Allocations set by this function are not checked against the bandwidth | ||
3029 | * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). | ||
3030 | * | ||
3031 | * Additionally, it is OK to call this function multiple times on the same | ||
3032 | * @port as needed. It is not OK however, to call this function and | ||
3033 | * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. | ||
3034 | * | ||
3035 | * See also: | ||
3036 | * drm_dp_atomic_release_vcpi_slots() | ||
3037 | * drm_dp_mst_atomic_check() | ||
3038 | * | ||
3039 | * Returns: | ||
3040 | * Total slots in the atomic state assigned for this port, or a negative error | ||
3041 | * code if the port no longer exists | ||
3022 | */ | 3042 | */ |
3023 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | 3043 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
3024 | struct drm_dp_mst_topology_mgr *mgr, | 3044 | struct drm_dp_mst_topology_mgr *mgr, |
3025 | struct drm_dp_mst_port *port, int pbn) | 3045 | struct drm_dp_mst_port *port, int pbn) |
3026 | { | 3046 | { |
3027 | struct drm_dp_mst_topology_state *topology_state; | 3047 | struct drm_dp_mst_topology_state *topology_state; |
3028 | int req_slots; | 3048 | struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; |
3049 | int prev_slots, req_slots, ret; | ||
3029 | 3050 | ||
3030 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | 3051 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); |
3031 | if (IS_ERR(topology_state)) | 3052 | if (IS_ERR(topology_state)) |
@@ -3034,20 +3055,54 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | |||
3034 | port = drm_dp_mst_topology_get_port_validated(mgr, port); | 3055 | port = drm_dp_mst_topology_get_port_validated(mgr, port); |
3035 | if (port == NULL) | 3056 | if (port == NULL) |
3036 | return -EINVAL; | 3057 | return -EINVAL; |
3037 | req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); | ||
3038 | DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", | ||
3039 | req_slots, topology_state->avail_slots); | ||
3040 | 3058 | ||
3041 | if (req_slots > topology_state->avail_slots) { | 3059 | /* Find the current allocation for this port, if any */ |
3042 | drm_dp_mst_topology_put_port(port); | 3060 | list_for_each_entry(pos, &topology_state->vcpis, next) { |
3043 | return -ENOSPC; | 3061 | if (pos->port == port) { |
3062 | vcpi = pos; | ||
3063 | prev_slots = vcpi->vcpi; | ||
3064 | |||
3065 | /* | ||
3066 | * This should never happen, unless the driver tries | ||
3067 | * releasing and allocating the same VCPI allocation, | ||
3068 | * which is an error | ||
3069 | */ | ||
3070 | if (WARN_ON(!prev_slots)) { | ||
3071 | DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", | ||
3072 | port); | ||
3073 | return -EINVAL; | ||
3074 | } | ||
3075 | |||
3076 | break; | ||
3077 | } | ||
3044 | } | 3078 | } |
3079 | if (!vcpi) | ||
3080 | prev_slots = 0; | ||
3081 | |||
3082 | req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); | ||
3083 | |||
3084 | DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", | ||
3085 | port->connector->base.id, port->connector->name, | ||
3086 | port, prev_slots, req_slots); | ||
3087 | |||
3088 | /* Add the new allocation to the state */ | ||
3089 | if (!vcpi) { | ||
3090 | vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); | ||
3091 | if (!vcpi) { | ||
3092 | ret = -ENOMEM; | ||
3093 | goto out; | ||
3094 | } | ||
3045 | 3095 | ||
3046 | topology_state->avail_slots -= req_slots; | 3096 | drm_dp_mst_get_port_malloc(port); |
3047 | DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); | 3097 | vcpi->port = port; |
3098 | list_add(&vcpi->next, &topology_state->vcpis); | ||
3099 | } | ||
3100 | vcpi->vcpi = req_slots; | ||
3048 | 3101 | ||
3102 | ret = req_slots; | ||
3103 | out: | ||
3049 | drm_dp_mst_topology_put_port(port); | 3104 | drm_dp_mst_topology_put_port(port); |
3050 | return req_slots; | 3105 | return ret; |
3051 | } | 3106 | } |
3052 | EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); | 3107 | EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); |
3053 | 3108 | ||
@@ -3055,31 +3110,57 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); | |||
3055 | * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots | 3110 | * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots |
3056 | * @state: global atomic state | 3111 | * @state: global atomic state |
3057 | * @mgr: MST topology manager for the port | 3112 | * @mgr: MST topology manager for the port |
3058 | * @slots: number of vcpi slots to release | 3113 | * @port: The port to release the VCPI slots from |
3059 | * | 3114 | * |
3060 | * RETURNS: | 3115 | * Releases any VCPI slots that have been allocated to a port in the atomic |
3061 | * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or | 3116 | * state. Any atomic drivers which support MST must call this function in |
3062 | * negative error code | 3117 | * their &drm_connector_helper_funcs.atomic_check() callback when the |
3118 | * connector will no longer have VCPI allocated (e.g. because it's CRTC was | ||
3119 | * removed) when it had VCPI allocated in the previous atomic state. | ||
3120 | * | ||
3121 | * It is OK to call this even if @port has been removed from the system. | ||
3122 | * Additionally, it is OK to call this function multiple times on the same | ||
3123 | * @port as needed. It is not OK however, to call this function and | ||
3124 | * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check | ||
3125 | * phase. | ||
3126 | * | ||
3127 | * See also: | ||
3128 | * drm_dp_atomic_find_vcpi_slots() | ||
3129 | * drm_dp_mst_atomic_check() | ||
3130 | * | ||
3131 | * Returns: | ||
3132 | * 0 if all slots for this port were added back to | ||
3133 | * &drm_dp_mst_topology_state.avail_slots or negative error code | ||
3063 | */ | 3134 | */ |
3064 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | 3135 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
3065 | struct drm_dp_mst_topology_mgr *mgr, | 3136 | struct drm_dp_mst_topology_mgr *mgr, |
3066 | int slots) | 3137 | struct drm_dp_mst_port *port) |
3067 | { | 3138 | { |
3068 | struct drm_dp_mst_topology_state *topology_state; | 3139 | struct drm_dp_mst_topology_state *topology_state; |
3140 | struct drm_dp_vcpi_allocation *pos; | ||
3141 | bool found = false; | ||
3069 | 3142 | ||
3070 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); | 3143 | topology_state = drm_atomic_get_mst_topology_state(state, mgr); |
3071 | if (IS_ERR(topology_state)) | 3144 | if (IS_ERR(topology_state)) |
3072 | return PTR_ERR(topology_state); | 3145 | return PTR_ERR(topology_state); |
3073 | 3146 | ||
3074 | /* We cannot rely on port->vcpi.num_slots to update | 3147 | list_for_each_entry(pos, &topology_state->vcpis, next) { |
3075 | * topology_state->avail_slots as the port may not exist if the parent | 3148 | if (pos->port == port) { |
3076 | * branch device was unplugged. This should be fixed by tracking | 3149 | found = true; |
3077 | * per-port slot allocation in drm_dp_mst_topology_state instead of | 3150 | break; |
3078 | * depending on the caller to tell us how many slots to release. | 3151 | } |
3079 | */ | 3152 | } |
3080 | topology_state->avail_slots += slots; | 3153 | if (WARN_ON(!found)) { |
3081 | DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", | 3154 | DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", |
3082 | slots, topology_state->avail_slots); | 3155 | port, &topology_state->base); |
3156 | return -EINVAL; | ||
3157 | } | ||
3158 | |||
3159 | DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); | ||
3160 | if (pos->vcpi) { | ||
3161 | drm_dp_mst_put_port_malloc(port); | ||
3162 | pos->vcpi = 0; | ||
3163 | } | ||
3083 | 3164 | ||
3084 | return 0; | 3165 | return 0; |
3085 | } | 3166 | } |
@@ -3501,15 +3582,41 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
3501 | static struct drm_private_state * | 3582 | static struct drm_private_state * |
3502 | drm_dp_mst_duplicate_state(struct drm_private_obj *obj) | 3583 | drm_dp_mst_duplicate_state(struct drm_private_obj *obj) |
3503 | { | 3584 | { |
3504 | struct drm_dp_mst_topology_state *state; | 3585 | struct drm_dp_mst_topology_state *state, *old_state = |
3586 | to_dp_mst_topology_state(obj->state); | ||
3587 | struct drm_dp_vcpi_allocation *pos, *vcpi; | ||
3505 | 3588 | ||
3506 | state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); | 3589 | state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); |
3507 | if (!state) | 3590 | if (!state) |
3508 | return NULL; | 3591 | return NULL; |
3509 | 3592 | ||
3510 | __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); | 3593 | __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); |
3511 | 3594 | ||
3595 | INIT_LIST_HEAD(&state->vcpis); | ||
3596 | |||
3597 | list_for_each_entry(pos, &old_state->vcpis, next) { | ||
3598 | /* Prune leftover freed VCPI allocations */ | ||
3599 | if (!pos->vcpi) | ||
3600 | continue; | ||
3601 | |||
3602 | vcpi = kmemdup(pos, sizeof(*vcpi), GFP_KERNEL); | ||
3603 | if (!vcpi) | ||
3604 | goto fail; | ||
3605 | |||
3606 | drm_dp_mst_get_port_malloc(vcpi->port); | ||
3607 | list_add(&vcpi->next, &state->vcpis); | ||
3608 | } | ||
3609 | |||
3512 | return &state->base; | 3610 | return &state->base; |
3611 | |||
3612 | fail: | ||
3613 | list_for_each_entry_safe(pos, vcpi, &state->vcpis, next) { | ||
3614 | drm_dp_mst_put_port_malloc(pos->port); | ||
3615 | kfree(pos); | ||
3616 | } | ||
3617 | kfree(state); | ||
3618 | |||
3619 | return NULL; | ||
3513 | } | 3620 | } |
3514 | 3621 | ||
3515 | static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, | 3622 | static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, |
@@ -3517,10 +3624,88 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, | |||
3517 | { | 3624 | { |
3518 | struct drm_dp_mst_topology_state *mst_state = | 3625 | struct drm_dp_mst_topology_state *mst_state = |
3519 | to_dp_mst_topology_state(state); | 3626 | to_dp_mst_topology_state(state); |
3627 | struct drm_dp_vcpi_allocation *pos, *tmp; | ||
3628 | |||
3629 | list_for_each_entry_safe(pos, tmp, &mst_state->vcpis, next) { | ||
3630 | /* We only keep references to ports with non-zero VCPIs */ | ||
3631 | if (pos->vcpi) | ||
3632 | drm_dp_mst_put_port_malloc(pos->port); | ||
3633 | kfree(pos); | ||
3634 | } | ||
3520 | 3635 | ||
3521 | kfree(mst_state); | 3636 | kfree(mst_state); |
3522 | } | 3637 | } |
3523 | 3638 | ||
3639 | static inline int | ||
3640 | drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, | ||
3641 | struct drm_dp_mst_topology_state *mst_state) | ||
3642 | { | ||
3643 | struct drm_dp_vcpi_allocation *vcpi; | ||
3644 | int avail_slots = 63; | ||
3645 | |||
3646 | list_for_each_entry(vcpi, &mst_state->vcpis, next) { | ||
3647 | /* Releasing VCPI is always OK-even if the port is gone */ | ||
3648 | if (!vcpi->vcpi) { | ||
3649 | DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", | ||
3650 | vcpi->port); | ||
3651 | continue; | ||
3652 | } | ||
3653 | |||
3654 | DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", | ||
3655 | vcpi->port, vcpi->vcpi); | ||
3656 | |||
3657 | avail_slots -= vcpi->vcpi; | ||
3658 | if (avail_slots < 0) { | ||
3659 | DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", | ||
3660 | vcpi->port, mst_state, | ||
3661 | avail_slots + vcpi->vcpi); | ||
3662 | return -ENOSPC; | ||
3663 | } | ||
3664 | } | ||
3665 | DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", | ||
3666 | mgr, mst_state, avail_slots, | ||
3667 | 63 - avail_slots); | ||
3668 | |||
3669 | return 0; | ||
3670 | } | ||
3671 | |||
3672 | /** | ||
3673 | * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an | ||
3674 | * atomic update is valid | ||
3675 | * @state: Pointer to the new &struct drm_dp_mst_topology_state | ||
3676 | * | ||
3677 | * Checks the given topology state for an atomic update to ensure that it's | ||
3678 | * valid. This includes checking whether there's enough bandwidth to support | ||
3679 | * the new VCPI allocations in the atomic update. | ||
3680 | * | ||
3681 | * Any atomic drivers supporting DP MST must make sure to call this after | ||
3682 | * checking the rest of their state in their | ||
3683 | * &drm_mode_config_funcs.atomic_check() callback. | ||
3684 | * | ||
3685 | * See also: | ||
3686 | * drm_dp_atomic_find_vcpi_slots() | ||
3687 | * drm_dp_atomic_release_vcpi_slots() | ||
3688 | * | ||
3689 | * Returns: | ||
3690 | * | ||
3691 | * 0 if the new state is valid, negative error code otherwise. | ||
3692 | */ | ||
3693 | int drm_dp_mst_atomic_check(struct drm_atomic_state *state) | ||
3694 | { | ||
3695 | struct drm_dp_mst_topology_mgr *mgr; | ||
3696 | struct drm_dp_mst_topology_state *mst_state; | ||
3697 | int i, ret = 0; | ||
3698 | |||
3699 | for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { | ||
3700 | ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); | ||
3701 | if (ret) | ||
3702 | break; | ||
3703 | } | ||
3704 | |||
3705 | return ret; | ||
3706 | } | ||
3707 | EXPORT_SYMBOL(drm_dp_mst_atomic_check); | ||
3708 | |||
3524 | const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { | 3709 | const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { |
3525 | .atomic_duplicate_state = drm_dp_mst_duplicate_state, | 3710 | .atomic_duplicate_state = drm_dp_mst_duplicate_state, |
3526 | .atomic_destroy_state = drm_dp_mst_destroy_state, | 3711 | .atomic_destroy_state = drm_dp_mst_destroy_state, |
@@ -3603,9 +3788,7 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, | |||
3603 | return -ENOMEM; | 3788 | return -ENOMEM; |
3604 | 3789 | ||
3605 | mst_state->mgr = mgr; | 3790 | mst_state->mgr = mgr; |
3606 | 3791 | INIT_LIST_HEAD(&mst_state->vcpis); | |
3607 | /* max. time slots - one slot for MTP header */ | ||
3608 | mst_state->avail_slots = 63; | ||
3609 | 3792 | ||
3610 | drm_atomic_private_obj_init(dev, &mgr->base, | 3793 | drm_atomic_private_obj_init(dev, &mgr->base, |
3611 | &mst_state->base, | 3794 | &mst_state->base, |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 812ec5ae5c7b..5a679af03a04 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -12623,6 +12623,10 @@ static int intel_atomic_check(struct drm_device *dev, | |||
12623 | "[modeset]" : "[fastset]"); | 12623 | "[modeset]" : "[fastset]"); |
12624 | } | 12624 | } |
12625 | 12625 | ||
12626 | ret = drm_dp_mst_atomic_check(state); | ||
12627 | if (ret) | ||
12628 | return ret; | ||
12629 | |||
12626 | if (any_ms) { | 12630 | if (any_ms) { |
12627 | ret = intel_modeset_checks(state); | 12631 | ret = intel_modeset_checks(state); |
12628 | 12632 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 631fd1537252..c8e2215628e6 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -41,8 +41,12 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
41 | struct drm_connector *connector = conn_state->connector; | 41 | struct drm_connector *connector = conn_state->connector; |
42 | void *port = to_intel_connector(connector)->port; | 42 | void *port = to_intel_connector(connector)->port; |
43 | struct drm_atomic_state *state = pipe_config->base.state; | 43 | struct drm_atomic_state *state = pipe_config->base.state; |
44 | struct drm_crtc *crtc = pipe_config->base.crtc; | ||
45 | struct drm_crtc_state *old_crtc_state = | ||
46 | drm_atomic_get_old_crtc_state(state, crtc); | ||
44 | int bpp; | 47 | int bpp; |
45 | int lane_count, slots = 0; | 48 | int lane_count, slots = |
49 | to_intel_crtc_state(old_crtc_state)->dp_m_n.tu; | ||
46 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; | 50 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
47 | int mst_pbn; | 51 | int mst_pbn; |
48 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, | 52 | bool constant_n = drm_dp_has_quirk(&intel_dp->desc, |
@@ -107,35 +111,39 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
107 | return true; | 111 | return true; |
108 | } | 112 | } |
109 | 113 | ||
110 | static int intel_dp_mst_atomic_check(struct drm_connector *connector, | 114 | static int |
111 | struct drm_connector_state *new_conn_state) | 115 | intel_dp_mst_atomic_check(struct drm_connector *connector, |
116 | struct drm_connector_state *new_conn_state) | ||
112 | { | 117 | { |
113 | struct drm_atomic_state *state = new_conn_state->state; | 118 | struct drm_atomic_state *state = new_conn_state->state; |
114 | struct drm_connector_state *old_conn_state; | 119 | struct drm_connector_state *old_conn_state = |
115 | struct drm_crtc *old_crtc; | 120 | drm_atomic_get_old_connector_state(state, connector); |
121 | struct intel_connector *intel_connector = | ||
122 | to_intel_connector(connector); | ||
123 | struct drm_crtc *new_crtc = new_conn_state->crtc; | ||
116 | struct drm_crtc_state *crtc_state; | 124 | struct drm_crtc_state *crtc_state; |
117 | int slots, ret = 0; | 125 | struct drm_dp_mst_topology_mgr *mgr; |
126 | int ret = 0; | ||
118 | 127 | ||
119 | old_conn_state = drm_atomic_get_old_connector_state(state, connector); | 128 | if (!old_conn_state->crtc) |
120 | old_crtc = old_conn_state->crtc; | 129 | return 0; |
121 | if (!old_crtc) | ||
122 | return ret; | ||
123 | |||
124 | crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); | ||
125 | slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; | ||
126 | if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { | ||
127 | struct drm_dp_mst_topology_mgr *mgr; | ||
128 | struct drm_encoder *old_encoder; | ||
129 | 130 | ||
130 | old_encoder = old_conn_state->best_encoder; | 131 | /* We only want to free VCPI if this state disables the CRTC on this |
131 | mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; | 132 | * connector |
133 | */ | ||
134 | if (new_crtc) { | ||
135 | crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); | ||
132 | 136 | ||
133 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); | 137 | if (!crtc_state || |
134 | if (ret) | 138 | !drm_atomic_crtc_needs_modeset(crtc_state) || |
135 | DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); | 139 | crtc_state->enable) |
136 | else | 140 | return 0; |
137 | to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; | ||
138 | } | 141 | } |
142 | |||
143 | mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr; | ||
144 | ret = drm_dp_atomic_release_vcpi_slots(state, mgr, | ||
145 | intel_connector->port); | ||
146 | |||
139 | return ret; | 147 | return ret; |
140 | } | 148 | } |
141 | 149 | ||
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 581163c8d7d7..451d020f0137 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -425,9 +425,15 @@ struct drm_dp_payload { | |||
425 | 425 | ||
426 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) | 426 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) |
427 | 427 | ||
428 | struct drm_dp_vcpi_allocation { | ||
429 | struct drm_dp_mst_port *port; | ||
430 | int vcpi; | ||
431 | struct list_head next; | ||
432 | }; | ||
433 | |||
428 | struct drm_dp_mst_topology_state { | 434 | struct drm_dp_mst_topology_state { |
429 | struct drm_private_state base; | 435 | struct drm_private_state base; |
430 | int avail_slots; | 436 | struct list_head vcpis; |
431 | struct drm_dp_mst_topology_mgr *mgr; | 437 | struct drm_dp_mst_topology_mgr *mgr; |
432 | }; | 438 | }; |
433 | 439 | ||
@@ -638,14 +644,17 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); | |||
638 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); | 644 | int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); |
639 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, | 645 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, |
640 | struct drm_dp_mst_topology_mgr *mgr); | 646 | struct drm_dp_mst_topology_mgr *mgr); |
641 | int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, | 647 | int __must_check |
642 | struct drm_dp_mst_topology_mgr *mgr, | 648 | drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
643 | struct drm_dp_mst_port *port, int pbn); | 649 | struct drm_dp_mst_topology_mgr *mgr, |
644 | int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, | 650 | struct drm_dp_mst_port *port, int pbn); |
645 | struct drm_dp_mst_topology_mgr *mgr, | 651 | int __must_check |
646 | int slots); | 652 | drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
653 | struct drm_dp_mst_topology_mgr *mgr, | ||
654 | struct drm_dp_mst_port *port); | ||
647 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, | 655 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, |
648 | struct drm_dp_mst_port *port, bool power_up); | 656 | struct drm_dp_mst_port *port, bool power_up); |
657 | int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); | ||
649 | 658 | ||
650 | void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); | 659 | void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); |
651 | void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); | 660 | void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); |