| .. | .. |
|---|
| 26 | 26 | #include <drm/drm_dp_helper.h> |
|---|
| 27 | 27 | #include <drm/drm_atomic.h> |
|---|
| 28 | 28 | |
|---|
| 29 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
|---|
| 30 | +#include <linux/stackdepot.h> |
|---|
| 31 | +#include <linux/timekeeping.h> |
|---|
| 32 | + |
|---|
| 33 | +enum drm_dp_mst_topology_ref_type { |
|---|
| 34 | + DRM_DP_MST_TOPOLOGY_REF_GET, |
|---|
| 35 | + DRM_DP_MST_TOPOLOGY_REF_PUT, |
|---|
| 36 | +}; |
|---|
| 37 | + |
|---|
| 38 | +struct drm_dp_mst_topology_ref_history { |
|---|
| 39 | + struct drm_dp_mst_topology_ref_entry { |
|---|
| 40 | + enum drm_dp_mst_topology_ref_type type; |
|---|
| 41 | + int count; |
|---|
| 42 | + ktime_t ts_nsec; |
|---|
| 43 | + depot_stack_handle_t backtrace; |
|---|
| 44 | + } *entries; |
|---|
| 45 | + int len; |
|---|
| 46 | +}; |
|---|
| 47 | +#endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */ |
|---|
| 48 | + |
|---|
| 29 | 49 | struct drm_dp_mst_branch; |
|---|
| 30 | | -struct drm_dp_mst_port; |
|---|
| 31 | 50 | |
|---|
| 32 | 51 | /** |
|---|
| 33 | 52 | * struct drm_dp_vcpi - Virtual Channel Payload Identifier |
|---|
| .. | .. |
|---|
| 43 | 62 | int num_slots; |
|---|
| 44 | 63 | }; |
|---|
| 45 | 64 | |
|---|
| 46 | | -struct drm_dp_mst_dsc_dpcd_cache { |
|---|
| 47 | | - bool valid; |
|---|
| 48 | | - bool use_parent_dpcd; |
|---|
| 49 | | - u8 dsc_dpcd[16]; |
|---|
| 50 | | -}; |
|---|
| 51 | | - |
|---|
| 52 | | -struct drm_dp_mst_dsc_info { |
|---|
| 53 | | - bool dsc_support; |
|---|
| 54 | | - struct drm_dp_mst_port *dsc_port; |
|---|
| 55 | | - struct drm_dp_mst_dsc_dpcd_cache dsc_dpcd_cache; |
|---|
| 56 | | -}; |
|---|
| 57 | | - |
|---|
| 58 | 65 | /** |
|---|
| 59 | 66 | * struct drm_dp_mst_port - MST port |
|---|
| 60 | | - * @kref: reference count for this port. |
|---|
| 61 | 67 | * @port_num: port number |
|---|
| 62 | | - * @input: if this port is an input port. |
|---|
| 63 | | - * @mcs: message capability status - DP 1.2 spec. |
|---|
| 64 | | - * @ddps: DisplayPort Device Plug Status - DP 1.2 |
|---|
| 65 | | - * @pdt: Peer Device Type |
|---|
| 66 | | - * @ldps: Legacy Device Plug Status |
|---|
| 67 | | - * @dpcd_rev: DPCD revision of device on this port |
|---|
| 68 | | - * @num_sdp_streams: Number of simultaneous streams |
|---|
| 69 | | - * @num_sdp_stream_sinks: Number of stream sinks |
|---|
| 70 | | - * @available_pbn: Available bandwidth for this port. |
|---|
| 68 | + * @input: if this port is an input port. Protected by |
|---|
| 69 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 70 | + * @mcs: message capability status - DP 1.2 spec. Protected by |
|---|
| 71 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 72 | + * @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by |
|---|
| 73 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 74 | + * @pdt: Peer Device Type. Protected by |
|---|
| 75 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 76 | + * @ldps: Legacy Device Plug Status. Protected by |
|---|
| 77 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 78 | + * @dpcd_rev: DPCD revision of device on this port. Protected by |
|---|
| 79 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 80 | + * @num_sdp_streams: Number of simultaneous streams. Protected by |
|---|
| 81 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 82 | + * @num_sdp_stream_sinks: Number of stream sinks. Protected by |
|---|
| 83 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 84 | + * @full_pbn: Max possible bandwidth for this port. Protected by |
|---|
| 85 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 71 | 86 | * @next: link to next port on this branch device |
|---|
| 72 | | - * @mstb: branch device attach below this port |
|---|
| 73 | | - * @aux: i2c aux transport to talk to device connected to this port. |
|---|
| 87 | + * @aux: i2c aux transport to talk to device connected to this port, protected |
|---|
| 88 | + * by &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 74 | 89 | * @parent: branch device parent of this port |
|---|
| 75 | 90 | * @vcpi: Virtual Channel Payload info for this port. |
|---|
| 76 | | - * @connector: DRM connector this port is connected to. |
|---|
| 91 | + * @connector: DRM connector this port is connected to. Protected by |
|---|
| 92 | + * &drm_dp_mst_topology_mgr.base.lock. |
|---|
| 77 | 93 | * @mgr: topology manager this port lives under. |
|---|
| 78 | 94 | * |
|---|
| 79 | 95 | * This structure represents an MST port endpoint on a device somewhere |
|---|
| 80 | 96 | * in the MST topology. |
|---|
| 81 | 97 | */ |
|---|
| 82 | 98 | struct drm_dp_mst_port { |
|---|
| 83 | | - struct kref kref; |
|---|
| 99 | + /** |
|---|
| 100 | + * @topology_kref: refcount for this port's lifetime in the topology, |
|---|
| 101 | + * only the DP MST helpers should need to touch this |
|---|
| 102 | + */ |
|---|
| 103 | + struct kref topology_kref; |
|---|
| 104 | + |
|---|
| 105 | + /** |
|---|
| 106 | + * @malloc_kref: refcount for the memory allocation containing this |
|---|
| 107 | + * structure. See drm_dp_mst_get_port_malloc() and |
|---|
| 108 | + * drm_dp_mst_put_port_malloc(). |
|---|
| 109 | + */ |
|---|
| 110 | + struct kref malloc_kref; |
|---|
| 111 | + |
|---|
| 112 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
|---|
| 113 | + /** |
|---|
| 114 | + * @topology_ref_history: A history of each topology |
|---|
| 115 | + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. |
|---|
| 116 | + */ |
|---|
| 117 | + struct drm_dp_mst_topology_ref_history topology_ref_history; |
|---|
| 118 | +#endif |
|---|
| 84 | 119 | |
|---|
| 85 | 120 | u8 port_num; |
|---|
| 86 | 121 | bool input; |
|---|
| .. | .. |
|---|
| 91 | 126 | u8 dpcd_rev; |
|---|
| 92 | 127 | u8 num_sdp_streams; |
|---|
| 93 | 128 | u8 num_sdp_stream_sinks; |
|---|
| 94 | | - uint16_t available_pbn; |
|---|
| 129 | + uint16_t full_pbn; |
|---|
| 95 | 130 | struct list_head next; |
|---|
| 96 | | - struct drm_dp_mst_branch *mstb; /* pointer to an mstb if this port has one */ |
|---|
| 131 | + /** |
|---|
| 132 | + * @mstb: the branch device connected to this port, if there is one. |
|---|
| 133 | + * This should be considered protected for reading by |
|---|
| 134 | + * &drm_dp_mst_topology_mgr.lock. There are two exceptions to this: |
|---|
| 135 | + * &drm_dp_mst_topology_mgr.up_req_work and |
|---|
| 136 | + * &drm_dp_mst_topology_mgr.work, which do not grab |
|---|
| 137 | + * &drm_dp_mst_topology_mgr.lock during reads but are the only |
|---|
| 138 | + * updaters of this list and are protected from writing concurrently |
|---|
| 139 | + * by &drm_dp_mst_topology_mgr.probe_lock. |
|---|
| 140 | + */ |
|---|
| 141 | + struct drm_dp_mst_branch *mstb; |
|---|
| 97 | 142 | struct drm_dp_aux aux; /* i2c bus for this port? */ |
|---|
| 98 | 143 | struct drm_dp_mst_branch *parent; |
|---|
| 99 | 144 | |
|---|
| .. | .. |
|---|
| 112 | 157 | */ |
|---|
| 113 | 158 | bool has_audio; |
|---|
| 114 | 159 | |
|---|
| 160 | + /** |
|---|
| 161 | + * @fec_capable: bool indicating if FEC can be supported up to that |
|---|
| 162 | + * point in the MST topology. |
|---|
| 163 | + */ |
|---|
| 115 | 164 | bool fec_capable; |
|---|
| 116 | | - |
|---|
| 117 | | - struct drm_dp_mst_dsc_info dsc_info; |
|---|
| 118 | 165 | }; |
|---|
| 119 | | - |
|---|
| 120 | | -/** |
|---|
| 121 | | - * struct drm_dp_mst_branch - MST branch device. |
|---|
| 122 | | - * @kref: reference count for this port. |
|---|
| 123 | | - * @rad: Relative Address to talk to this branch device. |
|---|
| 124 | | - * @lct: Link count total to talk to this branch device. |
|---|
| 125 | | - * @num_ports: number of ports on the branch. |
|---|
| 126 | | - * @msg_slots: one bit per transmitted msg slot. |
|---|
| 127 | | - * @ports: linked list of ports on this branch. |
|---|
| 128 | | - * @port_parent: pointer to the port parent, NULL if toplevel. |
|---|
| 129 | | - * @mgr: topology manager for this branch device. |
|---|
| 130 | | - * @tx_slots: transmission slots for this device. |
|---|
| 131 | | - * @last_seqno: last sequence number used to talk to this. |
|---|
| 132 | | - * @link_address_sent: if a link address message has been sent to this device yet. |
|---|
| 133 | | - * @guid: guid for DP 1.2 branch device. port under this branch can be |
|---|
| 134 | | - * identified by port #. |
|---|
| 135 | | - * |
|---|
| 136 | | - * This structure represents an MST branch device, there is one |
|---|
| 137 | | - * primary branch device at the root, along with any other branches connected |
|---|
| 138 | | - * to downstream port of parent branches. |
|---|
| 139 | | - */ |
|---|
| 140 | | -struct drm_dp_mst_branch { |
|---|
| 141 | | - struct kref kref; |
|---|
| 142 | | - u8 rad[8]; |
|---|
| 143 | | - u8 lct; |
|---|
| 144 | | - int num_ports; |
|---|
| 145 | | - |
|---|
| 146 | | - int msg_slots; |
|---|
| 147 | | - struct list_head ports; |
|---|
| 148 | | - |
|---|
| 149 | | - /* list of tx ops queue for this port */ |
|---|
| 150 | | - struct drm_dp_mst_port *port_parent; |
|---|
| 151 | | - struct drm_dp_mst_topology_mgr *mgr; |
|---|
| 152 | | - |
|---|
| 153 | | - /* slots are protected by mstb->mgr->qlock */ |
|---|
| 154 | | - struct drm_dp_sideband_msg_tx *tx_slots[2]; |
|---|
| 155 | | - int last_seqno; |
|---|
| 156 | | - bool link_address_sent; |
|---|
| 157 | | - |
|---|
| 158 | | - /* global unique identifier to identify branch devices */ |
|---|
| 159 | | - u8 guid[16]; |
|---|
| 160 | | -}; |
|---|
| 161 | | - |
|---|
| 162 | 166 | |
|---|
| 163 | 167 | /* sideband msg header - not bit struct */ |
|---|
| 164 | 168 | struct drm_dp_sideband_msg_hdr { |
|---|
| .. | .. |
|---|
| 172 | 176 | bool eomt; |
|---|
| 173 | 177 | bool seqno; |
|---|
| 174 | 178 | }; |
|---|
| 179 | + |
|---|
| 180 | +struct drm_dp_sideband_msg_rx { |
|---|
| 181 | + u8 chunk[48]; |
|---|
| 182 | + u8 msg[256]; |
|---|
| 183 | + u8 curchunk_len; |
|---|
| 184 | + u8 curchunk_idx; /* chunk we are parsing now */ |
|---|
| 185 | + u8 curchunk_hdrlen; |
|---|
| 186 | + u8 curlen; /* total length of the msg */ |
|---|
| 187 | + bool have_somt; |
|---|
| 188 | + bool have_eomt; |
|---|
| 189 | + struct drm_dp_sideband_msg_hdr initial_hdr; |
|---|
| 190 | +}; |
|---|
| 191 | + |
|---|
| 192 | +/** |
|---|
| 193 | + * struct drm_dp_mst_branch - MST branch device. |
|---|
| 194 | + * @rad: Relative Address to talk to this branch device. |
|---|
| 195 | + * @lct: Link count total to talk to this branch device. |
|---|
| 196 | + * @num_ports: number of ports on the branch. |
|---|
| 197 | + * @port_parent: pointer to the port parent, NULL if toplevel. |
|---|
| 198 | + * @mgr: topology manager for this branch device. |
|---|
| 199 | + * @link_address_sent: if a link address message has been sent to this device yet. |
|---|
| 200 | + * @guid: guid for DP 1.2 branch device. port under this branch can be |
|---|
| 201 | + * identified by port #. |
|---|
| 202 | + * |
|---|
| 203 | + * This structure represents an MST branch device, there is one |
|---|
| 204 | + * primary branch device at the root, along with any other branches connected |
|---|
| 205 | + * to downstream port of parent branches. |
|---|
| 206 | + */ |
|---|
| 207 | +struct drm_dp_mst_branch { |
|---|
| 208 | + /** |
|---|
| 209 | + * @topology_kref: refcount for this branch device's lifetime in the |
|---|
| 210 | + * topology, only the DP MST helpers should need to touch this |
|---|
| 211 | + */ |
|---|
| 212 | + struct kref topology_kref; |
|---|
| 213 | + |
|---|
| 214 | + /** |
|---|
| 215 | + * @malloc_kref: refcount for the memory allocation containing this |
|---|
| 216 | + * structure. See drm_dp_mst_get_mstb_malloc() and |
|---|
| 217 | + * drm_dp_mst_put_mstb_malloc(). |
|---|
| 218 | + */ |
|---|
| 219 | + struct kref malloc_kref; |
|---|
| 220 | + |
|---|
| 221 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
|---|
| 222 | + /** |
|---|
| 223 | + * @topology_ref_history: A history of each topology |
|---|
| 224 | + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. |
|---|
| 225 | + */ |
|---|
| 226 | + struct drm_dp_mst_topology_ref_history topology_ref_history; |
|---|
| 227 | +#endif |
|---|
| 228 | + |
|---|
| 229 | + /** |
|---|
| 230 | + * @destroy_next: linked-list entry used by |
|---|
| 231 | + * drm_dp_delayed_destroy_work() |
|---|
| 232 | + */ |
|---|
| 233 | + struct list_head destroy_next; |
|---|
| 234 | + |
|---|
| 235 | + u8 rad[8]; |
|---|
| 236 | + u8 lct; |
|---|
| 237 | + int num_ports; |
|---|
| 238 | + |
|---|
| 239 | + /** |
|---|
| 240 | + * @ports: the list of ports on this branch device. This should be |
|---|
| 241 | + * considered protected for reading by &drm_dp_mst_topology_mgr.lock. |
|---|
| 242 | + * There are two exceptions to this: |
|---|
| 243 | + * &drm_dp_mst_topology_mgr.up_req_work and |
|---|
| 244 | + * &drm_dp_mst_topology_mgr.work, which do not grab |
|---|
| 245 | + * &drm_dp_mst_topology_mgr.lock during reads but are the only |
|---|
| 246 | + * updaters of this list and are protected from updating the list |
|---|
| 247 | + * concurrently by @drm_dp_mst_topology_mgr.probe_lock |
|---|
| 248 | + */ |
|---|
| 249 | + struct list_head ports; |
|---|
| 250 | + |
|---|
| 251 | + struct drm_dp_mst_port *port_parent; |
|---|
| 252 | + struct drm_dp_mst_topology_mgr *mgr; |
|---|
| 253 | + |
|---|
| 254 | + bool link_address_sent; |
|---|
| 255 | + |
|---|
| 256 | + /* global unique identifier to identify branch devices */ |
|---|
| 257 | + u8 guid[16]; |
|---|
| 258 | +}; |
|---|
| 259 | + |
|---|
| 175 | 260 | |
|---|
| 176 | 261 | struct drm_dp_nak_reply { |
|---|
| 177 | 262 | u8 guid[16]; |
|---|
| .. | .. |
|---|
| 228 | 313 | u8 port_number; |
|---|
| 229 | 314 | }; |
|---|
| 230 | 315 | |
|---|
| 316 | +struct drm_dp_query_stream_enc_status_ack_reply { |
|---|
| 317 | + /* Bit[23:16]- Stream Id */ |
|---|
| 318 | + u8 stream_id; |
|---|
| 231 | 319 | |
|---|
| 232 | | -struct drm_dp_sideband_msg_rx { |
|---|
| 233 | | - u8 chunk[48]; |
|---|
| 234 | | - u8 msg[256]; |
|---|
| 235 | | - u8 curchunk_len; |
|---|
| 236 | | - u8 curchunk_idx; /* chunk we are parsing now */ |
|---|
| 237 | | - u8 curchunk_hdrlen; |
|---|
| 238 | | - u8 curlen; /* total length of the msg */ |
|---|
| 239 | | - bool have_somt; |
|---|
| 240 | | - bool have_eomt; |
|---|
| 241 | | - struct drm_dp_sideband_msg_hdr initial_hdr; |
|---|
| 320 | + /* Bit[15]- Signed */ |
|---|
| 321 | + bool reply_signed; |
|---|
| 322 | + |
|---|
| 323 | + /* Bit[10:8]- Stream Output Sink Type */ |
|---|
| 324 | + bool unauthorizable_device_present; |
|---|
| 325 | + bool legacy_device_present; |
|---|
| 326 | + bool query_capable_device_present; |
|---|
| 327 | + |
|---|
| 328 | + /* Bit[12:11]- Stream Output CP Type */ |
|---|
| 329 | + bool hdcp_1x_device_present; |
|---|
| 330 | + bool hdcp_2x_device_present; |
|---|
| 331 | + |
|---|
| 332 | + /* Bit[4]- Stream Authentication */ |
|---|
| 333 | + bool auth_completed; |
|---|
| 334 | + |
|---|
| 335 | + /* Bit[3]- Stream Encryption */ |
|---|
| 336 | + bool encryption_enabled; |
|---|
| 337 | + |
|---|
| 338 | + /* Bit[2]- Stream Repeater Function Present */ |
|---|
| 339 | + bool repeater_present; |
|---|
| 340 | + |
|---|
| 341 | + /* Bit[1:0]- Stream State */ |
|---|
| 342 | + u8 state; |
|---|
| 242 | 343 | }; |
|---|
| 243 | 344 | |
|---|
| 244 | 345 | #define DRM_DP_MAX_SDP_STREAMS 16 |
|---|
| .. | .. |
|---|
| 283 | 384 | struct drm_dp_remote_i2c_read { |
|---|
| 284 | 385 | u8 num_transactions; |
|---|
| 285 | 386 | u8 port_number; |
|---|
| 286 | | - struct { |
|---|
| 387 | + struct drm_dp_remote_i2c_read_tx { |
|---|
| 287 | 388 | u8 i2c_dev_id; |
|---|
| 288 | 389 | u8 num_bytes; |
|---|
| 289 | 390 | u8 *bytes; |
|---|
| .. | .. |
|---|
| 299 | 400 | u8 write_i2c_device_id; |
|---|
| 300 | 401 | u8 num_bytes; |
|---|
| 301 | 402 | u8 *bytes; |
|---|
| 403 | +}; |
|---|
| 404 | + |
|---|
| 405 | +struct drm_dp_query_stream_enc_status { |
|---|
| 406 | + u8 stream_id; |
|---|
| 407 | + u8 client_id[7]; /* 56-bit nonce */ |
|---|
| 408 | + u8 stream_event; |
|---|
| 409 | + bool valid_stream_event; |
|---|
| 410 | + u8 stream_behavior; |
|---|
| 411 | + u8 valid_stream_behavior; |
|---|
| 302 | 412 | }; |
|---|
| 303 | 413 | |
|---|
| 304 | 414 | /* this covers ENUM_RESOURCES, POWER_DOWN_PHY, POWER_UP_PHY */ |
|---|
| .. | .. |
|---|
| 349 | 459 | |
|---|
| 350 | 460 | struct drm_dp_remote_i2c_read i2c_read; |
|---|
| 351 | 461 | struct drm_dp_remote_i2c_write i2c_write; |
|---|
| 462 | + |
|---|
| 463 | + struct drm_dp_query_stream_enc_status enc_status; |
|---|
| 352 | 464 | } u; |
|---|
| 353 | 465 | }; |
|---|
| 354 | 466 | |
|---|
| .. | .. |
|---|
| 371 | 483 | struct drm_dp_remote_i2c_read_ack_reply remote_i2c_read_ack; |
|---|
| 372 | 484 | struct drm_dp_remote_i2c_read_nak_reply remote_i2c_read_nack; |
|---|
| 373 | 485 | struct drm_dp_remote_i2c_write_ack_reply remote_i2c_write_ack; |
|---|
| 486 | + |
|---|
| 487 | + struct drm_dp_query_stream_enc_status_ack_reply enc_status; |
|---|
| 374 | 488 | } u; |
|---|
| 375 | 489 | }; |
|---|
| 376 | 490 | |
|---|
| .. | .. |
|---|
| 402 | 516 | struct drm_dp_mst_topology_cbs { |
|---|
| 403 | 517 | /* create a connector for a port */ |
|---|
| 404 | 518 | struct drm_connector *(*add_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *path); |
|---|
| 405 | | - void (*register_connector)(struct drm_connector *connector); |
|---|
| 406 | | - void (*destroy_connector)(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 407 | | - struct drm_connector *connector); |
|---|
| 408 | | - void (*hotplug)(struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 409 | | - |
|---|
| 519 | + /* |
|---|
| 520 | + * Checks for any pending MST interrupts, passing them to MST core for |
|---|
| 521 | + * processing, the same way an HPD IRQ pulse handler would do this. |
|---|
| 522 | + * If provided MST core calls this callback from a poll-waiting loop |
|---|
| 523 | + * when waiting for MST down message replies. The driver is expected |
|---|
| 524 | + * to guard against a race between this callback and the driver's HPD |
|---|
| 525 | + * IRQ pulse handler. |
|---|
| 526 | + */ |
|---|
| 527 | + void (*poll_hpd_irq)(struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 410 | 528 | }; |
|---|
| 411 | 529 | |
|---|
| 412 | 530 | #define DP_MAX_PAYLOAD (sizeof(unsigned long) * 8) |
|---|
| .. | .. |
|---|
| 424 | 542 | |
|---|
| 425 | 543 | #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) |
|---|
| 426 | 544 | |
|---|
| 545 | +struct drm_dp_vcpi_allocation { |
|---|
| 546 | + struct drm_dp_mst_port *port; |
|---|
| 547 | + int vcpi; |
|---|
| 548 | + int pbn; |
|---|
| 549 | + bool dsc_enabled; |
|---|
| 550 | + struct list_head next; |
|---|
| 551 | +}; |
|---|
| 552 | + |
|---|
| 427 | 553 | struct drm_dp_mst_topology_state { |
|---|
| 428 | 554 | struct drm_private_state base; |
|---|
| 429 | | - int avail_slots; |
|---|
| 430 | | - struct drm_atomic_state *state; |
|---|
| 555 | + struct list_head vcpis; |
|---|
| 431 | 556 | struct drm_dp_mst_topology_mgr *mgr; |
|---|
| 432 | 557 | }; |
|---|
| 433 | 558 | |
|---|
| .. | .. |
|---|
| 475 | 600 | int conn_base_id; |
|---|
| 476 | 601 | |
|---|
| 477 | 602 | /** |
|---|
| 478 | | - * @down_rep_recv: Message receiver state for down replies. This and |
|---|
| 479 | | - * @up_req_recv are only ever access from the work item, which is |
|---|
| 480 | | - * serialised. |
|---|
| 481 | | - */ |
|---|
| 482 | | - struct drm_dp_sideband_msg_rx down_rep_recv; |
|---|
| 483 | | - /** |
|---|
| 484 | | - * @up_req_recv: Message receiver state for up requests. This and |
|---|
| 485 | | - * @down_rep_recv are only ever access from the work item, which is |
|---|
| 486 | | - * serialised. |
|---|
| 603 | + * @up_req_recv: Message receiver state for up requests. |
|---|
| 487 | 604 | */ |
|---|
| 488 | 605 | struct drm_dp_sideband_msg_rx up_req_recv; |
|---|
| 489 | 606 | |
|---|
| 490 | 607 | /** |
|---|
| 491 | | - * @lock: protects mst state, primary, dpcd. |
|---|
| 608 | + * @down_rep_recv: Message receiver state for replies to down |
|---|
| 609 | + * requests. |
|---|
| 610 | + */ |
|---|
| 611 | + struct drm_dp_sideband_msg_rx down_rep_recv; |
|---|
| 612 | + |
|---|
| 613 | + /** |
|---|
| 614 | + * @lock: protects @mst_state, @mst_primary, @dpcd, and |
|---|
| 615 | + * @payload_id_table_cleared. |
|---|
| 492 | 616 | */ |
|---|
| 493 | 617 | struct mutex lock; |
|---|
| 618 | + |
|---|
| 619 | + /** |
|---|
| 620 | + * @probe_lock: Prevents @work and @up_req_work, the only writers of |
|---|
| 621 | + * &drm_dp_mst_port.mstb and &drm_dp_mst_branch.ports, from racing |
|---|
| 622 | + * while they update the topology. |
|---|
| 623 | + */ |
|---|
| 624 | + struct mutex probe_lock; |
|---|
| 494 | 625 | |
|---|
| 495 | 626 | /** |
|---|
| 496 | 627 | * @mst_state: If this manager is enabled for an MST capable port. False |
|---|
| 497 | 628 | * if no MST sink/branch devices is connected. |
|---|
| 498 | 629 | */ |
|---|
| 499 | | - bool mst_state; |
|---|
| 630 | + bool mst_state : 1; |
|---|
| 631 | + |
|---|
| 632 | + /** |
|---|
| 633 | + * @payload_id_table_cleared: Whether or not we've cleared the payload |
|---|
| 634 | + * ID table for @mst_primary. Protected by @lock. |
|---|
| 635 | + */ |
|---|
| 636 | + bool payload_id_table_cleared : 1; |
|---|
| 637 | + |
|---|
| 500 | 638 | /** |
|---|
| 501 | 639 | * @mst_primary: Pointer to the primary/first branch device. |
|---|
| 502 | 640 | */ |
|---|
| .. | .. |
|---|
| 516 | 654 | int pbn_div; |
|---|
| 517 | 655 | |
|---|
| 518 | 656 | /** |
|---|
| 519 | | - * @state: State information for topology manager |
|---|
| 520 | | - */ |
|---|
| 521 | | - struct drm_dp_mst_topology_state *state; |
|---|
| 522 | | - |
|---|
| 523 | | - /** |
|---|
| 524 | 657 | * @funcs: Atomic helper callbacks |
|---|
| 525 | 658 | */ |
|---|
| 526 | 659 | const struct drm_private_state_funcs *funcs; |
|---|
| 527 | 660 | |
|---|
| 528 | 661 | /** |
|---|
| 529 | | - * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and |
|---|
| 530 | | - * &drm_dp_sideband_msg_tx.state once they are queued |
|---|
| 662 | + * @qlock: protects @tx_msg_downq and &drm_dp_sideband_msg_tx.state |
|---|
| 531 | 663 | */ |
|---|
| 532 | 664 | struct mutex qlock; |
|---|
| 665 | + |
|---|
| 533 | 666 | /** |
|---|
| 534 | | - * @tx_msg_downq: List of pending down replies. |
|---|
| 667 | + * @tx_msg_downq: List of pending down requests |
|---|
| 535 | 668 | */ |
|---|
| 536 | 669 | struct list_head tx_msg_downq; |
|---|
| 537 | 670 | |
|---|
| .. | .. |
|---|
| 541 | 674 | struct mutex payload_lock; |
|---|
| 542 | 675 | /** |
|---|
| 543 | 676 | * @proposed_vcpis: Array of pointers for the new VCPI allocation. The |
|---|
| 544 | | - * VCPI structure itself is &drm_dp_mst_port.vcpi. |
|---|
| 677 | + * VCPI structure itself is &drm_dp_mst_port.vcpi, and the size of |
|---|
| 678 | + * this array is determined by @max_payloads. |
|---|
| 545 | 679 | */ |
|---|
| 546 | 680 | struct drm_dp_vcpi **proposed_vcpis; |
|---|
| 547 | 681 | /** |
|---|
| 548 | | - * @payloads: Array of payloads. |
|---|
| 682 | + * @payloads: Array of payloads. The size of this array is determined |
|---|
| 683 | + * by @max_payloads. |
|---|
| 549 | 684 | */ |
|---|
| 550 | 685 | struct drm_dp_payload *payloads; |
|---|
| 551 | 686 | /** |
|---|
| .. | .. |
|---|
| 574 | 709 | struct work_struct tx_work; |
|---|
| 575 | 710 | |
|---|
| 576 | 711 | /** |
|---|
| 577 | | - * @destroy_connector_list: List of to be destroyed connectors. |
|---|
| 712 | + * @destroy_port_list: List of to be destroyed connectors. |
|---|
| 578 | 713 | */ |
|---|
| 579 | | - struct list_head destroy_connector_list; |
|---|
| 714 | + struct list_head destroy_port_list; |
|---|
| 580 | 715 | /** |
|---|
| 581 | | - * @destroy_connector_lock: Protects @connector_list. |
|---|
| 716 | + * @destroy_branch_device_list: List of to be destroyed branch |
|---|
| 717 | + * devices. |
|---|
| 582 | 718 | */ |
|---|
| 583 | | - struct mutex destroy_connector_lock; |
|---|
| 719 | + struct list_head destroy_branch_device_list; |
|---|
| 584 | 720 | /** |
|---|
| 585 | | - * @destroy_connector_work: Work item to destroy connectors. Needed to |
|---|
| 586 | | - * avoid locking inversion. |
|---|
| 721 | + * @delayed_destroy_lock: Protects @destroy_port_list and |
|---|
| 722 | + * @destroy_branch_device_list. |
|---|
| 587 | 723 | */ |
|---|
| 588 | | - struct work_struct destroy_connector_work; |
|---|
| 724 | + struct mutex delayed_destroy_lock; |
|---|
| 725 | + |
|---|
| 726 | + /** |
|---|
| 727 | + * @delayed_destroy_wq: Workqueue used for delayed_destroy_work items. |
|---|
| 728 | + * A dedicated WQ makes it possible to drain any requeued work items |
|---|
| 729 | + * on it. |
|---|
| 730 | + */ |
|---|
| 731 | + struct workqueue_struct *delayed_destroy_wq; |
|---|
| 732 | + |
|---|
| 733 | + /** |
|---|
| 734 | + * @delayed_destroy_work: Work item to destroy MST port and branch |
|---|
| 735 | + * devices, needed to avoid locking inversion. |
|---|
| 736 | + */ |
|---|
| 737 | + struct work_struct delayed_destroy_work; |
|---|
| 738 | + |
|---|
| 739 | + /** |
|---|
| 740 | + * @up_req_list: List of pending up requests from the topology that |
|---|
| 741 | + * need to be processed, in chronological order. |
|---|
| 742 | + */ |
|---|
| 743 | + struct list_head up_req_list; |
|---|
| 744 | + /** |
|---|
| 745 | + * @up_req_lock: Protects @up_req_list |
|---|
| 746 | + */ |
|---|
| 747 | + struct mutex up_req_lock; |
|---|
| 748 | + /** |
|---|
| 749 | + * @up_req_work: Work item to process up requests received from the |
|---|
| 750 | + * topology. Needed to avoid blocking hotplug handling and sideband |
|---|
| 751 | + * transmissions. |
|---|
| 752 | + */ |
|---|
| 753 | + struct work_struct up_req_work; |
|---|
| 754 | + |
|---|
| 755 | +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
|---|
| 756 | + /** |
|---|
| 757 | + * @topology_ref_history_lock: protects |
|---|
| 758 | + * &drm_dp_mst_port.topology_ref_history and |
|---|
| 759 | + * &drm_dp_mst_branch.topology_ref_history. |
|---|
| 760 | + */ |
|---|
| 761 | + struct mutex topology_ref_history_lock; |
|---|
| 762 | +#endif |
|---|
| 589 | 763 | }; |
|---|
| 590 | 764 | |
|---|
| 591 | 765 | int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| .. | .. |
|---|
| 595 | 769 | |
|---|
| 596 | 770 | void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 597 | 771 | |
|---|
| 598 | | - |
|---|
| 772 | +bool drm_dp_read_mst_cap(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE]); |
|---|
| 599 | 773 | int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state); |
|---|
| 600 | | - |
|---|
| 601 | 774 | |
|---|
| 602 | 775 | int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); |
|---|
| 603 | 776 | |
|---|
| 604 | 777 | |
|---|
| 605 | | -enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
|---|
| 606 | | - |
|---|
| 607 | | -bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 608 | | - struct drm_dp_mst_port *port); |
|---|
| 609 | | - |
|---|
| 610 | | -bool drm_dp_mst_has_fec(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 611 | | - struct drm_dp_mst_port *port); |
|---|
| 778 | +int |
|---|
| 779 | +drm_dp_mst_detect_port(struct drm_connector *connector, |
|---|
| 780 | + struct drm_modeset_acquire_ctx *ctx, |
|---|
| 781 | + struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 782 | + struct drm_dp_mst_port *port); |
|---|
| 612 | 783 | |
|---|
| 613 | 784 | struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
|---|
| 614 | 785 | |
|---|
| 786 | +int drm_dp_get_vc_payload_bw(int link_rate, int link_lane_count); |
|---|
| 615 | 787 | |
|---|
| 616 | | -int drm_dp_calc_pbn_mode(int clock, int bpp); |
|---|
| 617 | | - |
|---|
| 788 | +int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); |
|---|
| 618 | 789 | |
|---|
| 619 | 790 | bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 620 | 791 | struct drm_dp_mst_port *port, int pbn, int slots); |
|---|
| .. | .. |
|---|
| 644 | 815 | struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 645 | 816 | |
|---|
| 646 | 817 | void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 647 | | -int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 818 | +int __must_check |
|---|
| 819 | +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 820 | + bool sync); |
|---|
| 821 | + |
|---|
| 822 | +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, |
|---|
| 823 | + unsigned int offset, void *buffer, size_t size); |
|---|
| 824 | +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, |
|---|
| 825 | + unsigned int offset, void *buffer, size_t size); |
|---|
| 826 | + |
|---|
| 827 | +int drm_dp_mst_connector_late_register(struct drm_connector *connector, |
|---|
| 828 | + struct drm_dp_mst_port *port); |
|---|
| 829 | +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, |
|---|
| 830 | + struct drm_dp_mst_port *port); |
|---|
| 831 | + |
|---|
| 648 | 832 | struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, |
|---|
| 649 | 833 | struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 650 | | -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
|---|
| 651 | | - struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 652 | | - struct drm_dp_mst_port *port, int pbn); |
|---|
| 653 | | -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
|---|
| 654 | | - struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 655 | | - int slots); |
|---|
| 834 | +int __must_check |
|---|
| 835 | +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, |
|---|
| 836 | + struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 837 | + struct drm_dp_mst_port *port, int pbn, |
|---|
| 838 | + int pbn_div); |
|---|
| 839 | +int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, |
|---|
| 840 | + struct drm_dp_mst_port *port, |
|---|
| 841 | + int pbn, int pbn_div, |
|---|
| 842 | + bool enable); |
|---|
| 843 | +int __must_check |
|---|
| 844 | +drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, |
|---|
| 845 | + struct drm_dp_mst_topology_mgr *mgr); |
|---|
| 846 | +int __must_check |
|---|
| 847 | +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, |
|---|
| 848 | + struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 849 | + struct drm_dp_mst_port *port); |
|---|
| 656 | 850 | int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 657 | 851 | struct drm_dp_mst_port *port, bool power_up); |
|---|
| 852 | +int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 853 | + struct drm_dp_mst_port *port, |
|---|
| 854 | + struct drm_dp_query_stream_enc_status_ack_reply *status); |
|---|
| 855 | +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); |
|---|
| 658 | 856 | |
|---|
| 659 | | -int drm_dp_mst_get_dsc_info(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 660 | | - struct drm_dp_mst_port *port, |
|---|
| 661 | | - struct drm_dp_mst_dsc_info *dsc_info); |
|---|
| 857 | +void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); |
|---|
| 858 | +void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); |
|---|
| 662 | 859 | |
|---|
| 663 | | -int drm_dp_mst_update_dsc_info(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 664 | | - struct drm_dp_mst_port *port, |
|---|
| 665 | | - struct drm_dp_mst_dsc_info *dsc_info); |
|---|
| 860 | +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); |
|---|
| 666 | 861 | |
|---|
| 667 | | -int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 668 | | - struct drm_dp_mst_port *port, |
|---|
| 669 | | - int offset, int size, u8 *bytes); |
|---|
| 862 | +extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; |
|---|
| 670 | 863 | |
|---|
| 671 | | -int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 672 | | - struct drm_dp_mst_port *port, |
|---|
| 673 | | - int offset, int size, u8 *bytes); |
|---|
| 864 | +/** |
|---|
| 865 | + * __drm_dp_mst_state_iter_get - private atomic state iterator function for |
|---|
| 866 | + * macro-internal use |
|---|
| 867 | + * @state: &struct drm_atomic_state pointer |
|---|
| 868 | + * @mgr: pointer to the &struct drm_dp_mst_topology_mgr iteration cursor |
|---|
| 869 | + * @old_state: optional pointer to the old &struct drm_dp_mst_topology_state |
|---|
| 870 | + * iteration cursor |
|---|
| 871 | + * @new_state: optional pointer to the new &struct drm_dp_mst_topology_state |
|---|
| 872 | + * iteration cursor |
|---|
| 873 | + * @i: int iteration cursor, for macro-internal use |
|---|
| 874 | + * |
|---|
| 875 | + * Used by for_each_oldnew_mst_mgr_in_state(), |
|---|
| 876 | + * for_each_old_mst_mgr_in_state(), and for_each_new_mst_mgr_in_state(). Don't |
|---|
| 877 | + * call this directly. |
|---|
| 878 | + * |
|---|
| 879 | + * Returns: |
|---|
| 880 | + * True if the current &struct drm_private_obj is a &struct |
|---|
| 881 | + * drm_dp_mst_topology_mgr, false otherwise. |
|---|
| 882 | + */ |
|---|
| 883 | +static inline bool |
|---|
| 884 | +__drm_dp_mst_state_iter_get(struct drm_atomic_state *state, |
|---|
| 885 | + struct drm_dp_mst_topology_mgr **mgr, |
|---|
| 886 | + struct drm_dp_mst_topology_state **old_state, |
|---|
| 887 | + struct drm_dp_mst_topology_state **new_state, |
|---|
| 888 | + int i) |
|---|
| 889 | +{ |
|---|
| 890 | + struct __drm_private_objs_state *objs_state = &state->private_objs[i]; |
|---|
| 674 | 891 | |
|---|
| 675 | | -int drm_dp_mst_get_max_sdp_streams_supported( |
|---|
| 676 | | - struct drm_dp_mst_topology_mgr *mgr, |
|---|
| 677 | | - struct drm_dp_mst_port *port); |
|---|
| 892 | + if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) |
|---|
| 893 | + return false; |
|---|
| 894 | + |
|---|
| 895 | + *mgr = to_dp_mst_topology_mgr(objs_state->ptr); |
|---|
| 896 | + if (old_state) |
|---|
| 897 | + *old_state = to_dp_mst_topology_state(objs_state->old_state); |
|---|
| 898 | + if (new_state) |
|---|
| 899 | + *new_state = to_dp_mst_topology_state(objs_state->new_state); |
|---|
| 900 | + |
|---|
| 901 | + return true; |
|---|
| 902 | +} |
|---|
| 903 | + |
|---|
| 904 | +/** |
|---|
| 905 | + * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology |
|---|
| 906 | + * managers in an atomic update |
|---|
| 907 | + * @__state: &struct drm_atomic_state pointer |
|---|
| 908 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
|---|
| 909 | + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old |
|---|
| 910 | + * state |
|---|
| 911 | + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new |
|---|
| 912 | + * state |
|---|
| 913 | + * @__i: int iteration cursor, for macro-internal use |
|---|
| 914 | + * |
|---|
| 915 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
|---|
| 916 | + * tracking both old and new state. This is useful in places where the state |
|---|
| 917 | + * delta needs to be considered, for example in atomic check functions. |
|---|
| 918 | + */ |
|---|
| 919 | +#define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ |
|---|
| 920 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
|---|
| 921 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) |
|---|
| 922 | + |
|---|
| 923 | +/** |
|---|
| 924 | + * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers |
|---|
| 925 | + * in an atomic update |
|---|
| 926 | + * @__state: &struct drm_atomic_state pointer |
|---|
| 927 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
|---|
| 928 | + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old |
|---|
| 929 | + * state |
|---|
| 930 | + * @__i: int iteration cursor, for macro-internal use |
|---|
| 931 | + * |
|---|
| 932 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
|---|
| 933 | + * tracking only the old state. This is useful in disable functions, where we |
|---|
| 934 | + * need the old state the hardware is still in. |
|---|
| 935 | + */ |
|---|
| 936 | +#define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ |
|---|
| 937 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
|---|
| 938 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) |
|---|
| 939 | + |
|---|
| 940 | +/** |
|---|
| 941 | + * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers |
|---|
| 942 | + * in an atomic update |
|---|
| 943 | + * @__state: &struct drm_atomic_state pointer |
|---|
| 944 | + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor |
|---|
| 945 | + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new |
|---|
| 946 | + * state |
|---|
| 947 | + * @__i: int iteration cursor, for macro-internal use |
|---|
| 948 | + * |
|---|
| 949 | + * This iterates over all DRM DP MST topology managers in an atomic update, |
|---|
| 950 | + * tracking only the new state. This is useful in enable functions, where we |
|---|
| 951 | + * need the new state the hardware should be in when the atomic commit |
|---|
| 952 | + * operation has completed. |
|---|
| 953 | + */ |
|---|
| 954 | +#define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ |
|---|
| 955 | + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ |
|---|
| 956 | + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) |
|---|
| 678 | 957 | |
|---|
| 679 | 958 | #endif |
|---|