diff options
| author | Daniel Vetter <[email protected]> | 2017-12-13 13:49:36 +0100 |
|---|---|---|
| committer | Daniel Vetter <[email protected]> | 2017-12-13 22:59:00 +0100 |
| commit | ea497bb92064875497554ee7cdf10df7fb7393fc (patch) | |
| tree | 2bfa08868034b4143432a897f172bf3aa98f1331 /include | |
| parent | 4b4df570b41dbb421f52605357d5d56c872df6d9 (diff) | |
drm: rework delayed connector cleanup in connector_iter
PROBE_DEFER also uses system_wq to reprobe drivers, which means when
that again fails, and we try to flush the overall system_wq (to get
all the delayed connectore cleanup work_struct completed), we
deadlock.
Fix this by using just a single cleanup work, so that we can only
flush that one and don't block on anything else. That means a free
list plus locking, a standard pattern.
v2:
- Correctly free connectors only on last ref. Oops (Chris).
- use llist_head/node (Chris).
v3
- Add init_llist_head (Chris).
Fixes: a703c55004e1 ("drm: safely free connectors from connector_iter")
Fixes: 613051dac40d ("drm: locking&new iterators for connector_list")
Cc: Ben Widawsky <[email protected]>
Cc: Dave Airlie <[email protected]>
Cc: Chris Wilson <[email protected]>
Cc: Sean Paul <[email protected]>
Cc: <[email protected]> # v4.11+: 613051dac40d ("drm: locking&new iterators for connector_list"
Cc: <[email protected]> # v4.11+
Cc: Daniel Vetter <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Gustavo Padovan <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Javier Martinez Canillas <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Guillaume Tucker <[email protected]>
Cc: Mark Brown <[email protected]>
Cc: Kevin Hilman <[email protected]>
Cc: Matt Hart <[email protected]>
Cc: Thierry Escande <[email protected]>
Cc: Tomeu Vizoso <[email protected]>
Cc: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Chris Wilson <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
Diffstat (limited to 'include')
| -rw-r--r-- | include/drm/drm_connector.h | 10 | ||||
| -rw-r--r-- | include/drm/drm_mode_config.h | 18 |
2 files changed, 23 insertions, 5 deletions
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a4649c56ca2f..5971577016a2 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -24,6 +24,7 @@ #define __DRM_CONNECTOR_H__ #include <linux/list.h> +#include <linux/llist.h> #include <linux/ctype.h> #include <linux/hdmi.h> #include <drm/drm_mode_object.h> @@ -918,12 +919,13 @@ struct drm_connector { uint16_t tile_h_size, tile_v_size; /** - * @free_work: + * @free_node: * - * Work used only by &drm_connector_iter to be able to clean up a - * connector from any context. + * List used only by &drm_connector_iter to be able to clean up a + * connector from any context, in conjunction with + * &drm_mode_config.connector_free_work. */ - struct work_struct free_work; + struct llist_node free_node; }; #define obj_to_connector(x) container_of(x, struct drm_connector, base) diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index b21e827c5c78..b0ce26d71296 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -27,6 +27,7 @@ #include <linux/types.h> #include <linux/idr.h> #include <linux/workqueue.h> +#include <linux/llist.h> #include <drm/drm_modeset_lock.h> @@ -393,7 +394,7 @@ struct drm_mode_config { /** * @connector_list_lock: Protects @num_connector and - * @connector_list. + * @connector_list and @connector_free_list. */ spinlock_t connector_list_lock; /** @@ -414,6 +415,21 @@ struct drm_mode_config { */ struct list_head connector_list; /** + * @connector_free_list: + * + * List of connector objects linked with &drm_connector.free_head. + * Protected by @connector_list_lock. Used by + * drm_for_each_connector_iter() and + * &struct drm_connector_list_iter to savely free connectors using + * @connector_free_work. + */ + struct llist_head connector_free_list; + /** + * @connector_free_work: Work to clean up @connector_free_list. + */ + struct work_struct connector_free_work; + + /** * @num_encoder: * * Number of encoders on this device. This is invariant over the |