Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/dp_mst: Protect drm_dp_mst_port members with locking

This is a complicated one. Essentially, there's currently a problem in the MST
core that hasn't really caused any issues that we're aware of (emphasis on "that
we're aware of"): locking.

When we go through and probe the link addresses and path resources in a
topology, we hold no locks when updating ports with said information. The
members I'm referring to in particular are:

- ldps
- ddps
- mcs
- pdt
- dpcd_rev
- num_sdp_streams
- num_sdp_stream_sinks
- available_pbn
- input
- connector

Now that we're handling UP requests asynchronously and will be using some of
the struct members mentioned above in atomic modesetting in the future for
features such as PBN validation, this is going to become a lot more important.
As well, the next few commits that prepare us for and introduce suspend/resume
reprobing will also need clear locking in order to prevent from additional
racing hilarities that we never could have hit in the past.

So, let's solve this issue by using &mgr->base.lock, the modesetting
lock which currently only protects &mgr->base.state. This works
perfectly because it allows us to avoid blocking connection_mutex
unnecessarily, and we can grab this in connector detection paths since
it's a ww mutex. We start by having drm_dp_mst_handle_up_req() hold this
when updating ports. For drm_dp_mst_handle_link_address_port() things
are a bit more complicated. As I've learned the hard way, we can grab
&mgr->lock.base for everything except for port->connector. See, our
normal driver probing paths end up generating this rather obvious
lockdep chain:

&drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex

However, sysfs grabs &drm->mode_config.mutex in order to protect itself
from connector state changing under it. Because this entails grabbing
kn->count, e.g. the lock that the kernel provides for protecting sysfs
contexts, we end up grabbing kn->count followed by
&drm->mode_config.mutex. This ends up creating an extremely rude chain:

&kn->count
-> &drm->mode_config.mutex
-> crtc_ww_class_mutex/crtc_ww_class_acquire
-> &connector->mutex

I mean, look at that thing! It's just evil!!! This gross thing ends up
making any calls to drm_connector_register()/drm_connector_unregister()
impossible when holding any kind of modesetting lock. This is annoying
because ideally, we always want to ensure that
drm_dp_mst_port->connector never changes when doing an atomic commit or
check that would affect the atomic topology state so that it can
reliably and easily be used from future DRM DP MST helpers to assist
with tasks such as scanning through the current VCPI allocations and
adding connectors which need to have their allocations updated in
response to a bandwidth change or the like.

Being able to hold &mgr->base.lock throughout the entire link probe
process would have been _great_, since we could prevent userspace from
ever seeing any states in-between individual port changes and as a
result likely end up with a much faster probe and more consistent
results from said probes. But without some rework of how we handle
connector probing in sysfs it's not at all currently possible. In the
future, maybe we can try using the sysfs locks to protect updates to
connector probing state and fix this mess.

So for now, to protect everything other than port->connector under
&mgr->base.lock and ensure that we still have the guarantee that atomic
check/commit contexts will never see port->connector change we use a
silly trick. See: port->connector only needs to change in order to
ensure that input ports (see the MST spec) never have a ghost connector
associated with them. But, there's nothing stopping us from simply
throwing the entire port out and creating a new one in order to maintain
that requirement while still keeping port->connector consistent across
the lifetime of the port in atomic check/commit contexts. For all
intended purposes this works fine, as we validate ports in any contexts
we care about before using them and as such will end up reporting the
connector as disconnected until it's port's destruction finalizes. So,
we just do that in cases where we detect port->input has transitioned
from true->false. We don't need to worry about the other direction,
since a port without a connector isn't visible to userspace and as such
doesn't need to be protected by &mgr->base.lock until we finish
registering a connector for it.

For updating members of drm_dp_mst_port other than port->connector, we
simply grab &mgr->base.lock in drm_dp_mst_link_probe_work() for already
registered ports, update said members and drop the lock before
potentially registering a connector and probing the link address of it's
children.

Finally, we modify drm_dp_mst_detect_port() to take a modesetting lock
acquisition context in order to acquire &mgr->base.lock under
&connection_mutex and convert all it's users over to using the
.detect_ctx probe hooks.

With that, we finally have well defined locking.

Changes since v4:
* Get rid of port->mutex, stop using connection_mutex and just use our own
modesetting lock - mgr->base.lock. Also, add a probe_lock that comes
before this patch.
* Just throw out ports that get changed from an output to an input, and
replace them with new ports. This lets us ensure that modesetting
contexts never see port->connector go from having a connector to being
NULL.
* Write an extremely detailed explanation of what problems this is
trying to fix, since there's a _lot_ of context here and I honestly
forgot some of it myself a couple times.
* Don't grab mgr->lock when reading port->mstb in
drm_dp_mst_handle_link_address_port(). It's not needed.

Cc: Juston Li <juston.li@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <sean@poorly.run>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191022023641.8026-7-lyude@redhat.com

+240 -140
+12 -16
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
··· 123 123 return result; 124 124 } 125 125 126 - static enum drm_connector_status 127 - dm_dp_mst_detect(struct drm_connector *connector, bool force) 128 - { 129 - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); 130 - struct amdgpu_dm_connector *master = aconnector->mst_port; 131 - 132 - enum drm_connector_status status = 133 - drm_dp_mst_detect_port( 134 - connector, 135 - &master->mst_mgr, 136 - aconnector->port); 137 - 138 - return status; 139 - } 140 - 141 126 static void 142 127 dm_dp_mst_connector_destroy(struct drm_connector *connector) 143 128 { ··· 162 177 } 163 178 164 179 static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { 165 - .detect = dm_dp_mst_detect, 166 180 .fill_modes = drm_helper_probe_single_connector_modes, 167 181 .destroy = dm_dp_mst_connector_destroy, 168 182 .reset = amdgpu_dm_connector_funcs_reset, ··· 236 252 return &amdgpu_dm_connector->mst_encoder->base; 237 253 } 238 254 255 + static int 256 + dm_dp_mst_detect(struct drm_connector *connector, 257 + struct drm_modeset_acquire_ctx *ctx, bool force) 258 + { 259 + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); 260 + struct amdgpu_dm_connector *master = aconnector->mst_port; 261 + 262 + return drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr, 263 + aconnector->port); 264 + } 265 + 239 266 static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = { 240 267 .get_modes = dm_dp_mst_get_modes, 241 268 .mode_valid = amdgpu_dm_connector_mode_valid, 242 269 .best_encoder = dm_mst_best_encoder, 270 + .detect_ctx = dm_dp_mst_detect, 243 271 }; 244 272 245 273 static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
+157 -73
drivers/gpu/drm/drm_dp_mst_topology.c
··· 1906 1906 EXPORT_SYMBOL(drm_dp_mst_connector_early_unregister); 1907 1907 1908 1908 static void 1909 + drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb, 1910 + struct drm_dp_mst_port *port) 1911 + { 1912 + struct drm_dp_mst_topology_mgr *mgr = port->mgr; 1913 + char proppath[255]; 1914 + int ret; 1915 + 1916 + build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath)); 1917 + port->connector = mgr->cbs->add_connector(mgr, port, proppath); 1918 + if (!port->connector) { 1919 + ret = -ENOMEM; 1920 + goto error; 1921 + } 1922 + 1923 + if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || 1924 + port->pdt == DP_PEER_DEVICE_SST_SINK) && 1925 + port->port_num >= DP_MST_LOGICAL_PORT_0) { 1926 + port->cached_edid = drm_get_edid(port->connector, 1927 + &port->aux.ddc); 1928 + drm_connector_set_tile_property(port->connector); 1929 + } 1930 + 1931 + mgr->cbs->register_connector(port->connector); 1932 + return; 1933 + 1934 + error: 1935 + DRM_ERROR("Failed to create connector for port %p: %d\n", port, ret); 1936 + } 1937 + 1938 + /* 1939 + * Drop a topology reference, and unlink the port from the in-memory topology 1940 + * layout 1941 + */ 1942 + static void 1943 + drm_dp_mst_topology_unlink_port(struct drm_dp_mst_topology_mgr *mgr, 1944 + struct drm_dp_mst_port *port) 1945 + { 1946 + mutex_lock(&mgr->lock); 1947 + list_del(&port->next); 1948 + mutex_unlock(&mgr->lock); 1949 + drm_dp_mst_topology_put_port(port); 1950 + } 1951 + 1952 + static struct drm_dp_mst_port * 1953 + drm_dp_mst_add_port(struct drm_device *dev, 1954 + struct drm_dp_mst_topology_mgr *mgr, 1955 + struct drm_dp_mst_branch *mstb, u8 port_number) 1956 + { 1957 + struct drm_dp_mst_port *port = kzalloc(sizeof(*port), GFP_KERNEL); 1958 + 1959 + if (!port) 1960 + return NULL; 1961 + 1962 + kref_init(&port->topology_kref); 1963 + kref_init(&port->malloc_kref); 1964 + port->parent = mstb; 1965 + port->port_num = port_number; 1966 + port->mgr = mgr; 1967 + port->aux.name = "DPMST"; 1968 + port->aux.dev = dev->dev; 1969 + port->aux.is_remote = true; 1970 + 1971 + /* 1972 + * Make sure the memory allocation for our parent branch stays 1973 + * around until our own memory allocation is released 1974 + */ 1975 + drm_dp_mst_get_mstb_malloc(mstb); 1976 + 1977 + return port; 1978 + } 1979 + 1980 + static void 1909 1981 drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, 1910 1982 struct drm_device *dev, 1911 1983 struct drm_dp_link_addr_reply_port *port_msg) 1912 1984 { 1913 1985 struct drm_dp_mst_topology_mgr *mgr = mstb->mgr; 1914 1986 struct drm_dp_mst_port *port; 1915 - bool created = false; 1916 - int old_ddps = 0; 1987 + int old_ddps = 0, ret; 1988 + u8 new_pdt = DP_PEER_DEVICE_NONE; 1989 + bool created = false, send_link_addr = false; 1917 1990 1918 1991 port = drm_dp_get_port(mstb, port_msg->port_number); 1919 1992 if (!port) { 1920 - port = kzalloc(sizeof(*port), GFP_KERNEL); 1993 + port = drm_dp_mst_add_port(dev, mgr, mstb, 1994 + port_msg->port_number); 1921 1995 if (!port) 1922 1996 return; 1923 - kref_init(&port->topology_kref); 1924 - kref_init(&port->malloc_kref); 1925 - port->parent = mstb; 1926 - port->port_num = port_msg->port_number; 1927 - port->mgr = mgr; 1928 - port->aux.name = "DPMST"; 1929 - port->aux.dev = dev->dev; 1930 - port->aux.is_remote = true; 1931 - 1932 - /* 1933 - * Make sure the memory allocation for our parent branch stays 1934 - * around until our own memory allocation is released 1997 + created = true; 1998 + } else if (port_msg->input_port && !port->input && port->connector) { 1999 + /* Destroying the connector is impossible in this context, so 2000 + * replace the port with a new one 1935 2001 */ 1936 - drm_dp_mst_get_mstb_malloc(mstb); 2002 + drm_dp_mst_topology_unlink_port(mgr, port); 2003 + drm_dp_mst_topology_put_port(port); 1937 2004 2005 + port = drm_dp_mst_add_port(dev, mgr, mstb, 2006 + port_msg->port_number); 2007 + if (!port) 2008 + return; 1938 2009 created = true; 1939 2010 } else { 2011 + /* Locking is only needed when the port has a connector 2012 + * exposed to userspace 2013 + */ 2014 + drm_modeset_lock(&mgr->base.lock, NULL); 1940 2015 old_ddps = port->ddps; 1941 2016 } 1942 2017 1943 2018 port->input = port_msg->input_port; 2019 + if (!port->input) 2020 + new_pdt = port_msg->peer_device_type; 1944 2021 port->mcs = port_msg->mcs; 1945 2022 port->ddps = port_msg->ddps; 1946 2023 port->ldps = port_msg->legacy_device_plug_status; ··· 2045 1968 } 2046 1969 } 2047 1970 2048 - if (!port->input) { 2049 - int ret = drm_dp_port_set_pdt(port, 2050 - port_msg->peer_device_type); 2051 - if (ret == 1) { 2052 - drm_dp_send_link_address(mgr, port->mstb); 2053 - } else if (ret < 0) { 2054 - DRM_ERROR("Failed to change PDT on port %p: %d\n", 2055 - port, ret); 2056 - goto fail; 2057 - } 1971 + ret = drm_dp_port_set_pdt(port, new_pdt); 1972 + if (ret == 1) { 1973 + send_link_addr = true; 1974 + } else if (ret < 0) { 1975 + DRM_ERROR("Failed to change PDT on port %p: %d\n", 1976 + port, ret); 1977 + goto fail; 2058 1978 } 2059 1979 2060 - if (created && !port->input) { 2061 - char proppath[255]; 1980 + if (!created) 1981 + drm_modeset_unlock(&mgr->base.lock); 1982 + else if (!port->connector && !port->input) 1983 + drm_dp_mst_port_add_connector(mstb, port); 2062 1984 2063 - build_mst_prop_path(mstb, port->port_num, proppath, 2064 - sizeof(proppath)); 2065 - port->connector = (*mgr->cbs->add_connector)(mgr, port, 2066 - proppath); 2067 - if (!port->connector) 2068 - goto fail; 2069 - 2070 - if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || 2071 - port->pdt == DP_PEER_DEVICE_SST_SINK) && 2072 - port->port_num >= DP_MST_LOGICAL_PORT_0) { 2073 - port->cached_edid = drm_get_edid(port->connector, 2074 - &port->aux.ddc); 2075 - drm_connector_set_tile_property(port->connector); 2076 - } 2077 - 2078 - (*mgr->cbs->register_connector)(port->connector); 2079 - } 1985 + if (send_link_addr && port->mstb) 1986 + drm_dp_send_link_address(mgr, port->mstb); 2080 1987 2081 1988 /* put reference to this port */ 2082 1989 drm_dp_mst_topology_put_port(port); 2083 1990 return; 2084 1991 2085 1992 fail: 2086 - /* Remove it from the port list */ 2087 - mutex_lock(&mgr->lock); 2088 - list_del(&port->next); 2089 - mutex_unlock(&mgr->lock); 2090 - 2091 - /* Drop the port list reference */ 1993 + drm_dp_mst_topology_unlink_port(mgr, port); 2092 1994 drm_dp_mst_topology_put_port(port); 2093 - /* And now drop our reference */ 2094 - drm_dp_mst_topology_put_port(port); 1995 + if (!created) 1996 + drm_modeset_unlock(&mgr->base.lock); 2095 1997 } 2096 1998 2097 1999 static void 2098 2000 drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, 2099 2001 struct drm_dp_connection_status_notify *conn_stat) 2100 2002 { 2003 + struct drm_dp_mst_topology_mgr *mgr = mstb->mgr; 2101 2004 struct drm_dp_mst_port *port; 2102 2005 int old_ddps; 2103 2006 bool dowork = false; ··· 2085 2028 port = drm_dp_get_port(mstb, conn_stat->port_number); 2086 2029 if (!port) 2087 2030 return; 2031 + 2032 + /* Locking is only needed if the port's exposed to userspace */ 2033 + if (port->connector) 2034 + drm_modeset_lock(&mgr->base.lock, NULL); 2088 2035 2089 2036 old_ddps = port->ddps; 2090 2037 port->mcs = conn_stat->message_capability_status; ··· 2115 2054 } 2116 2055 } 2117 2056 2057 + if (port->connector) 2058 + drm_modeset_unlock(&mgr->base.lock); 2059 + 2118 2060 drm_dp_mst_topology_put_port(port); 2119 2061 if (dowork) 2120 2062 queue_work(system_long_wq, &mstb->mgr->work); 2121 - 2122 2063 } 2123 2064 2124 2065 static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_topology_mgr *mgr, ··· 2220 2157 if (port->input || !port->ddps) 2221 2158 continue; 2222 2159 2223 - if (!port->available_pbn) 2160 + if (!port->available_pbn) { 2161 + drm_modeset_lock(&mgr->base.lock, NULL); 2224 2162 drm_dp_send_enum_path_resources(mgr, mstb, port); 2163 + drm_modeset_unlock(&mgr->base.lock); 2164 + } 2225 2165 2226 2166 if (port->mstb) 2227 2167 mstb_child = drm_dp_mst_topology_get_mstb_validated( ··· 2255 2189 mstb = NULL; 2256 2190 } 2257 2191 mutex_unlock(&mgr->lock); 2258 - if (mstb) { 2259 - drm_dp_check_and_send_link_address(mgr, mstb); 2260 - drm_dp_mst_topology_put_mstb(mstb); 2192 + if (!mstb) { 2193 + mutex_unlock(&mgr->probe_lock); 2194 + return; 2261 2195 } 2196 + 2197 + drm_dp_check_and_send_link_address(mgr, mstb); 2198 + drm_dp_mst_topology_put_mstb(mstb); 2199 + 2262 2200 mutex_unlock(&mgr->probe_lock); 2201 + drm_kms_helper_hotplug_event(dev); 2263 2202 } 2264 2203 2265 2204 static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, ··· 2548 2477 for (i = 0; i < reply->nports; i++) 2549 2478 drm_dp_mst_handle_link_address_port(mstb, mgr->dev, 2550 2479 &reply->ports[i]); 2551 - 2552 - drm_kms_helper_hotplug_event(mgr->dev); 2553 2480 2554 2481 out: 2555 2482 if (ret <= 0) ··· 3343 3274 return 0; 3344 3275 } 3345 3276 3346 - static inline void 3277 + static inline bool 3347 3278 drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr, 3348 3279 struct drm_dp_pending_up_req *up_req) 3349 3280 { 3350 3281 struct drm_dp_mst_branch *mstb = NULL; 3351 3282 struct drm_dp_sideband_msg_req_body *msg = &up_req->msg; 3352 3283 struct drm_dp_sideband_msg_hdr *hdr = &up_req->hdr; 3284 + bool hotplug = false; 3353 3285 3354 3286 if (hdr->broadcast) { 3355 3287 const u8 *guid = NULL; ··· 3368 3298 if (!mstb) { 3369 3299 DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", 3370 3300 hdr->lct); 3371 - return; 3301 + return false; 3372 3302 } 3373 3303 3374 3304 /* TODO: Add missing handler for DP_RESOURCE_STATUS_NOTIFY events */ 3375 3305 if (msg->req_type == DP_CONNECTION_STATUS_NOTIFY) { 3376 3306 drm_dp_mst_handle_conn_stat(mstb, &msg->u.conn_stat); 3377 - drm_kms_helper_hotplug_event(mgr->dev); 3307 + hotplug = true; 3378 3308 } 3379 3309 3380 3310 drm_dp_mst_topology_put_mstb(mstb); 3311 + return hotplug; 3381 3312 } 3382 3313 3383 3314 static void drm_dp_mst_up_req_work(struct work_struct *work) ··· 3387 3316 container_of(work, struct drm_dp_mst_topology_mgr, 3388 3317 up_req_work); 3389 3318 struct drm_dp_pending_up_req *up_req; 3319 + bool send_hotplug = false; 3390 3320 3391 3321 mutex_lock(&mgr->probe_lock); 3392 3322 while (true) { ··· 3402 3330 if (!up_req) 3403 3331 break; 3404 3332 3405 - drm_dp_mst_process_up_req(mgr, up_req); 3333 + send_hotplug |= drm_dp_mst_process_up_req(mgr, up_req); 3406 3334 kfree(up_req); 3407 3335 } 3408 3336 mutex_unlock(&mgr->probe_lock); 3337 + 3338 + if (send_hotplug) 3339 + drm_kms_helper_hotplug_event(mgr->dev); 3409 3340 } 3410 3341 3411 3342 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) ··· 3516 3441 /** 3517 3442 * drm_dp_mst_detect_port() - get connection status for an MST port 3518 3443 * @connector: DRM connector for this port 3444 + * @ctx: The acquisition context to use for grabbing locks 3519 3445 * @mgr: manager for this port 3520 - * @port: unverified pointer to a port 3446 + * @port: pointer to a port 3521 3447 * 3522 - * This returns the current connection state for a port. It validates the 3523 - * port pointer still exists so the caller doesn't require a reference 3448 + * This returns the current connection state for a port. 3524 3449 */ 3525 - enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, 3526 - struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) 3450 + int 3451 + drm_dp_mst_detect_port(struct drm_connector *connector, 3452 + struct drm_modeset_acquire_ctx *ctx, 3453 + struct drm_dp_mst_topology_mgr *mgr, 3454 + struct drm_dp_mst_port *port) 3527 3455 { 3528 - enum drm_connector_status status = connector_status_disconnected; 3456 + int ret; 3529 3457 3530 3458 /* we need to search for the port in the mgr in case it's gone */ 3531 3459 port = drm_dp_mst_topology_get_port_validated(mgr, port); 3532 3460 if (!port) 3533 3461 return connector_status_disconnected; 3462 + 3463 + ret = drm_modeset_lock(&mgr->base.lock, ctx); 3464 + if (ret) 3465 + goto out; 3466 + 3467 + ret = connector_status_disconnected; 3534 3468 3535 3469 if (!port->ddps) 3536 3470 goto out; ··· 3550 3466 break; 3551 3467 3552 3468 case DP_PEER_DEVICE_SST_SINK: 3553 - status = connector_status_connected; 3469 + ret = connector_status_connected; 3554 3470 /* for logical ports - cache the EDID */ 3555 3471 if (port->port_num >= 8 && !port->cached_edid) { 3556 3472 port->cached_edid = drm_get_edid(connector, &port->aux.ddc); ··· 3558 3474 break; 3559 3475 case DP_PEER_DEVICE_DP_LEGACY_CONV: 3560 3476 if (port->ldps) 3561 - status = connector_status_connected; 3477 + ret = connector_status_connected; 3562 3478 break; 3563 3479 } 3564 3480 out: 3565 3481 drm_dp_mst_topology_put_port(port); 3566 - return status; 3482 + return ret; 3567 3483 } 3568 3484 EXPORT_SYMBOL(drm_dp_mst_detect_port); 3569 3485
+15 -13
drivers/gpu/drm/i915/display/intel_dp_mst.c
··· 391 391 return ret; 392 392 } 393 393 394 - static enum drm_connector_status 395 - intel_dp_mst_detect(struct drm_connector *connector, bool force) 396 - { 397 - struct intel_connector *intel_connector = to_intel_connector(connector); 398 - struct intel_dp *intel_dp = intel_connector->mst_port; 399 - 400 - if (drm_connector_is_unregistered(connector)) 401 - return connector_status_disconnected; 402 - return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, 403 - intel_connector->port); 404 - } 405 - 406 394 static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { 407 - .detect = intel_dp_mst_detect, 408 395 .fill_modes = drm_helper_probe_single_connector_modes, 409 396 .atomic_get_property = intel_digital_connector_atomic_get_property, 410 397 .atomic_set_property = intel_digital_connector_atomic_set_property, ··· 452 465 return &intel_dp->mst_encoders[crtc->pipe]->base.base; 453 466 } 454 467 468 + static int 469 + intel_dp_mst_detect(struct drm_connector *connector, 470 + struct drm_modeset_acquire_ctx *ctx, bool force) 471 + { 472 + struct intel_connector *intel_connector = to_intel_connector(connector); 473 + struct intel_dp *intel_dp = intel_connector->mst_port; 474 + 475 + if (drm_connector_is_unregistered(connector)) 476 + return connector_status_disconnected; 477 + 478 + return drm_dp_mst_detect_port(connector, ctx, &intel_dp->mst_mgr, 479 + intel_connector->port); 480 + } 481 + 455 482 static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { 456 483 .get_modes = intel_dp_mst_get_modes, 457 484 .mode_valid = intel_dp_mst_mode_valid, 458 485 .atomic_best_encoder = intel_mst_atomic_best_encoder, 459 486 .atomic_check = intel_dp_mst_atomic_check, 487 + .detect_ctx = intel_dp_mst_detect, 460 488 }; 461 489 462 490 static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+16 -16
drivers/gpu/drm/nouveau/dispnv50/disp.c
··· 986 986 return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); 987 987 } 988 988 989 - static const struct drm_connector_helper_funcs 990 - nv50_mstc_help = { 991 - .get_modes = nv50_mstc_get_modes, 992 - .mode_valid = nv50_mstc_mode_valid, 993 - .best_encoder = nv50_mstc_best_encoder, 994 - .atomic_best_encoder = nv50_mstc_atomic_best_encoder, 995 - .atomic_check = nv50_mstc_atomic_check, 996 - }; 997 - 998 - static enum drm_connector_status 999 - nv50_mstc_detect(struct drm_connector *connector, bool force) 989 + static int 990 + nv50_mstc_detect(struct drm_connector *connector, 991 + struct drm_modeset_acquire_ctx *ctx, bool force) 1000 992 { 1001 993 struct nv50_mstc *mstc = nv50_mstc(connector); 1002 - enum drm_connector_status conn_status; 1003 994 int ret; 1004 995 1005 996 if (drm_connector_is_unregistered(connector)) ··· 1000 1009 if (ret < 0 && ret != -EACCES) 1001 1010 return connector_status_disconnected; 1002 1011 1003 - conn_status = drm_dp_mst_detect_port(connector, mstc->port->mgr, 1004 - mstc->port); 1012 + ret = drm_dp_mst_detect_port(connector, ctx, mstc->port->mgr, 1013 + mstc->port); 1005 1014 1006 1015 pm_runtime_mark_last_busy(connector->dev->dev); 1007 1016 pm_runtime_put_autosuspend(connector->dev->dev); 1008 - return conn_status; 1017 + return ret; 1009 1018 } 1019 + 1020 + static const struct drm_connector_helper_funcs 1021 + nv50_mstc_help = { 1022 + .get_modes = nv50_mstc_get_modes, 1023 + .mode_valid = nv50_mstc_mode_valid, 1024 + .best_encoder = nv50_mstc_best_encoder, 1025 + .atomic_best_encoder = nv50_mstc_atomic_best_encoder, 1026 + .atomic_check = nv50_mstc_atomic_check, 1027 + .detect_ctx = nv50_mstc_detect, 1028 + }; 1010 1029 1011 1030 static void 1012 1031 nv50_mstc_destroy(struct drm_connector *connector) ··· 1032 1031 static const struct drm_connector_funcs 1033 1032 nv50_mstc = { 1034 1033 .reset = nouveau_conn_reset, 1035 - .detect = nv50_mstc_detect, 1036 1034 .fill_modes = drm_helper_probe_single_connector_modes, 1037 1035 .destroy = nv50_mstc_destroy, 1038 1036 .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
+14 -10
drivers/gpu/drm/radeon/radeon_dp_mst.c
··· 233 233 return &radeon_connector->mst_encoder->base; 234 234 } 235 235 236 + static int 237 + radeon_dp_mst_detect(struct drm_connector *connector, 238 + struct drm_modeset_acquire_ctx *ctx, 239 + bool force) 240 + { 241 + struct radeon_connector *radeon_connector = 242 + to_radeon_connector(connector); 243 + struct radeon_connector *master = radeon_connector->mst_port; 244 + 245 + return drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr, 246 + radeon_connector->port); 247 + } 248 + 236 249 static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = { 237 250 .get_modes = radeon_dp_mst_get_modes, 238 251 .mode_valid = radeon_dp_mst_mode_valid, 239 252 .best_encoder = radeon_mst_best_encoder, 253 + .detect_ctx = radeon_dp_mst_detect, 240 254 }; 241 - 242 - static enum drm_connector_status 243 - radeon_dp_mst_detect(struct drm_connector *connector, bool force) 244 - { 245 - struct radeon_connector *radeon_connector = to_radeon_connector(connector); 246 - struct radeon_connector *master = radeon_connector->mst_port; 247 - 248 - return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port); 249 - } 250 255 251 256 static void 252 257 radeon_dp_mst_connector_destroy(struct drm_connector *connector) ··· 267 262 268 263 static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = { 269 264 .dpms = drm_helper_connector_dpms, 270 - .detect = radeon_dp_mst_detect, 271 265 .fill_modes = drm_helper_probe_single_connector_modes, 272 266 .destroy = radeon_dp_mst_connector_destroy, 273 267 };
+26 -12
include/drm/drm_dp_mst_helper.h
··· 45 45 /** 46 46 * struct drm_dp_mst_port - MST port 47 47 * @port_num: port number 48 - * @input: if this port is an input port. 49 - * @mcs: message capability status - DP 1.2 spec. 50 - * @ddps: DisplayPort Device Plug Status - DP 1.2 51 - * @pdt: Peer Device Type 52 - * @ldps: Legacy Device Plug Status 53 - * @dpcd_rev: DPCD revision of device on this port 54 - * @num_sdp_streams: Number of simultaneous streams 55 - * @num_sdp_stream_sinks: Number of stream sinks 56 - * @available_pbn: Available bandwidth for this port. 48 + * @input: if this port is an input port. Protected by 49 + * &drm_dp_mst_topology_mgr.base.lock. 50 + * @mcs: message capability status - DP 1.2 spec. Protected by 51 + * &drm_dp_mst_topology_mgr.base.lock. 52 + * @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by 53 + * &drm_dp_mst_topology_mgr.base.lock. 54 + * @pdt: Peer Device Type. Protected by 55 + * &drm_dp_mst_topology_mgr.base.lock. 56 + * @ldps: Legacy Device Plug Status. Protected by 57 + * &drm_dp_mst_topology_mgr.base.lock. 58 + * @dpcd_rev: DPCD revision of device on this port. Protected by 59 + * &drm_dp_mst_topology_mgr.base.lock. 60 + * @num_sdp_streams: Number of simultaneous streams. Protected by 61 + * &drm_dp_mst_topology_mgr.base.lock. 62 + * @num_sdp_stream_sinks: Number of stream sinks. Protected by 63 + * &drm_dp_mst_topology_mgr.base.lock. 64 + * @available_pbn: Available bandwidth for this port. Protected by 65 + * &drm_dp_mst_topology_mgr.base.lock. 57 66 * @next: link to next port on this branch device 58 67 * @aux: i2c aux transport to talk to device connected to this port, protected 59 - * by &drm_dp_mst_topology_mgr.lock 68 + * by &drm_dp_mst_topology_mgr.base.lock. 60 69 * @parent: branch device parent of this port 61 70 * @vcpi: Virtual Channel Payload info for this port. 62 - * @connector: DRM connector this port is connected to. 71 + * @connector: DRM connector this port is connected to. Protected by 72 + * &drm_dp_mst_topology_mgr.base.lock. 63 73 * @mgr: topology manager this port lives under. 64 74 * 65 75 * This structure represents an MST port endpoint on a device somewhere ··· 663 653 int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); 664 654 665 655 666 - 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); 656 + int 657 + drm_dp_mst_detect_port(struct drm_connector *connector, 658 + struct drm_modeset_acquire_ctx *ctx, 659 + struct drm_dp_mst_topology_mgr *mgr, 660 + struct drm_dp_mst_port *port); 667 661 668 662 bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, 669 663 struct drm_dp_mst_port *port);