From: Marek Szyprowski <m.szyprowski@samsung.com>
To: Daniel Vetter <daniel.vetter@ffwll.ch>,
Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Cc: Ben Widawsky <ben@bwidawsk.net>,
Tomeu Vizoso <tomeu.vizoso@collabora.com>,
David Airlie <airlied@linux.ie>, Mark Brown <broonie@kernel.org>,
Shuah Khan <shuahkh@osg.samsung.com>,
DRI Development <dri-devel@lists.freedesktop.org>,
Thierry Escande <thierry.escande@collabora.co.uk>,
Guillaume Tucker <guillaume.tucker@collabora.com>,
stable@vger.kernel.org,
Enric Balletbo i Serra <enric.balletbo@collabora.com>,
Daniel Vetter <daniel.vetter@intel.com>,
Javier Martinez Canillas <javier@dowhile0.org>,
Kevin Hilman <khilman@baylibre.com>,
Matt Hart <matthew.hart@linaro.org>
Subject: Re: [PATCH] drm: rework delayed connector cleanup in connector_iter
Date: Wed, 13 Dec 2017 13:27:37 +0100 [thread overview]
Message-ID: <2afb1fd9-fc9f-df1e-2a97-1071764ed9b0@samsung.com> (raw)
In-Reply-To: <20171213104553.30821-1-daniel.vetter@ffwll.ch>
Hi Daniel,
On 2017-12-13 11:45, Daniel Vetter wrote:
> 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.
>
> Fixes: a703c55004e1 ("drm: safely free connectors from connector_iter")
> Fixes: 613051dac40d ("drm: locking&new iterators for connector_list")
> Cc: Ben Widawsky <ben@bwidawsk.net>
> Cc: Dave Airlie <airlied@gmail.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Sean Paul <seanpaul@chromium.org>
> Cc: <stable@vger.kernel.org> # v4.11+: 613051dac40d ("drm: locking&new iterators for connector_list"
> Cc: <stable@vger.kernel.org> # v4.11+
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Gustavo Padovan <gustavo@padovan.org>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Javier Martinez Canillas <javier@dowhile0.org>
> Cc: Shuah Khan <shuahkh@osg.samsung.com>
> Cc: Guillaume Tucker <guillaume.tucker@collabora.com>
> Cc: Mark Brown <broonie@kernel.org>
> Cc: Kevin Hilman <khilman@baylibre.com>
> Cc: Matt Hart <matthew.hart@linaro.org>
> Cc: Thierry Escande <thierry.escande@collabora.co.uk>
> Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
> Cc: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Sadly, this patch doesn't work in my test environment (Samsung Snow
Chromebook with modified DTS), which reproduces the problem discussed
inhttps://www.spinics.net/lists/arm-kernel/msg622332.html
[ 4.925178] exynos-drm exynos-drm: failed to bind 14530000.hdmi (ops
hdmi_component_ops): -19
[ 4.936167] Unable to handle kernel paging request at virtual address
fffffcac
[ 4.942004] pgd = ad8213ad
[ 4.944654] [fffffcac] *pgd=6fffd861, *pte=00000000, *ppte=00000000
[ 4.950944] Internal error: Oops: 37 [#1] PREEMPT SMP ARM
[ 4.956284] Modules linked in:
[ 4.959324] CPU: 1 PID: 80 Comm: kworker/1:3 Not tainted
4.15.0-rc3-next-20171212-00004-g879e6206b6fb-dirty #56
[ 4.969391] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[ 4.975472] Workqueue: events drm_connector_free_work_fn
[ 4.980765] PC is at drm_mode_object_unregister+0x1c/0x48
[ 4.986146] LR is at __mutex_lock+0x3ec/0xa0c
[ 4.990483] pc : [<c050e744>] lr : [<c0a0465c>] psr: 60000113
[ 4.996731] sp : ed27dec0 ip : ed27c000 fp : ed25042c
[ 5.001940] r10: 00000000 r9 : c1008c6c r8 : c10ae6d4
[ 5.007148] r7 : ed2503ec r6 : ed250000 r5 : fffffcac r4 : ed250330
[ 5.013659] r3 : 00000000 r2 : 00000001 r1 : ed27de50 r0 : 00000000
[ 5.020170] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM
Segment none
[ 5.027286] Control: 10c5387d Table: 4000406a DAC: 00000051
[ 5.033016] Process kworker/1:3 (pid: 80, stack limit = 0x37cd389f)
[ 5.039265] Stack: (0xed27dec0 to 0xed27e000)
[ 5.043607] dec0: fffffc98 ed27ded0 ed250000 c050d374 ed242f78
ed242f78 00000001 ed22e200
[ 5.051766] dee0: eefc91c0 eefcc500 c10ad21d c0143438 00000001
00000000 c0143384 c0143534
[ 5.059925] df00: 00000001 00000000 c0143384 00000000 edd0ce00
c181658c c1214a78 00000000
[ 5.068084] df20: c0d7c514 00000000 c120f048 ed22e200 ed22e218
eefc91f8 c0143ae8 c10ae166
[ 5.076243] df40: 00000008 ed22e218 c1005d00 c0143a2c eefcc5f5
ed22e200 eefc91c0 c0143c4c
[ 5.084402] df60: c0a09894 ed709100 00000000 ed709100 00000000
ed25e000 ed709180 ed22e200
[ 5.092561] df80: edfdfe68 c0143a3c 00000000 c014a1c4 ed25e000
c014a074 00000000 00000000
[ 5.100720] dfa0: 00000000 00000000 00000000 c01010b4 00000000
00000000 00000000 00000000
[ 5.108879] dfc0: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 5.117039] dfe0: 00000000 00000000 00000000 00000000 00000013
00000000 00000000 00000000
[ 5.125202] [<c050e744>] (drm_mode_object_unregister) from
[<c050d374>] (drm_connector_free_work_fn+0x80/0xa8)
[ 5.135185] [<c050d374>] (drm_connector_free_work_fn) from
[<c0143438>] (process_one_work+0x1dc/0x7a8)
[ 5.144472] [<c0143438>] (process_one_work) from [<c0143a2c>]
(process_scheduled_works+0x28/0x38)
[ 5.153324] [<c0143a2c>] (process_scheduled_works) from [<c0143c4c>]
(worker_thread+0x210/0x4dc)
[ 5.162092] [<c0143c4c>] (worker_thread) from [<c014a1c4>]
(kthread+0x150/0x19c)
[ 5.169469] [<c014a1c4>] (kthread) from [<c01010b4>]
(ret_from_fork+0x14/0x20)
[ 5.176669] Exception stack(0xed27dfb0 to 0xed27dff8)
[ 5.181704] dfa0: 00000000
00000000 00000000 00000000
[ 5.189864] dfc0: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[ 5.198023] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 5.204622] Code: e1a06000 e3a01000 e1a00004 eb13d968 (e5951000)
[ 5.210731] ---[ end trace 55b8b9b30581db4f ]---
I will try to provide a bit more details soon.
> ---
> drivers/gpu/drm/drm_connector.c | 46 ++++++++++++++++++++++++++-----------
> drivers/gpu/drm/drm_crtc_internal.h | 1 +
> drivers/gpu/drm/drm_mode_config.c | 5 +++-
> include/drm/drm_connector.h | 4 ++--
> include/drm/drm_mode_config.h | 17 +++++++++++++-
> 5 files changed, 55 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 0b7e0974e6da..2f43dc217936 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -153,14 +153,23 @@ static void drm_connector_free(struct kref *kref)
> connector->funcs->destroy(connector);
> }
>
> -static void drm_connector_free_work_fn(struct work_struct *work)
> +void drm_connector_free_work_fn(struct work_struct *work)
> {
> - struct drm_connector *connector =
> - container_of(work, struct drm_connector, free_work);
> - struct drm_device *dev = connector->dev;
> + struct drm_connector *connector;
> + struct drm_device *dev =
> + container_of(work, struct drm_device, mode_config.connector_free_work);
> + struct drm_mode_config *config = &dev->mode_config;
> + unsigned long flags;
> + LIST_HEAD(list_head);
>
> - drm_mode_object_unregister(dev, &connector->base);
> - connector->funcs->destroy(connector);
> + spin_lock_irqsave(&config->connector_list_lock, flags);
> + list_splice(&config->connector_free_list, &list_head);
> + spin_unlock_irqrestore(&config->connector_list_lock, flags);
> +
> + list_for_each_entry(connector, &list_head, free_head) {
> + drm_mode_object_unregister(dev, &connector->base);
> + connector->funcs->destroy(connector);
> + }
> }
>
> /**
> @@ -192,8 +201,6 @@ int drm_connector_init(struct drm_device *dev,
> if (ret)
> return ret;
>
> - INIT_WORK(&connector->free_work, drm_connector_free_work_fn);
> -
> connector->base.properties = &connector->properties;
> connector->dev = dev;
> connector->funcs = funcs;
> @@ -550,10 +557,15 @@ EXPORT_SYMBOL(drm_connector_list_iter_begin);
> * actually release the connector when dropping our final reference.
> */
> static void
> -drm_connector_put_safe(struct drm_connector *conn)
> +__drm_connector_put_safe(struct drm_connector *conn)
> {
> + struct drm_mode_config *config = &conn->dev->mode_config;
> +
> + lockdep_assert_held(&config->connector_list_lock);
> + list_add(&conn->free_head, &config->connector_free_list);
> +
> if (refcount_dec_and_test(&conn->base.refcount.refcount))
> - schedule_work(&conn->free_work);
> + schedule_work(&config->connector_free_work);
> }
>
> /**
> @@ -585,10 +597,10 @@ drm_connector_list_iter_next(struct drm_connector_list_iter *iter)
>
> /* loop until it's not a zombie connector */
> } while (!kref_get_unless_zero(&iter->conn->base.refcount));
> - spin_unlock_irqrestore(&config->connector_list_lock, flags);
>
> if (old_conn)
> - drm_connector_put_safe(old_conn);
> + __drm_connector_put_safe(old_conn);
> + spin_unlock_irqrestore(&config->connector_list_lock, flags);
>
> return iter->conn;
> }
> @@ -605,9 +617,15 @@ EXPORT_SYMBOL(drm_connector_list_iter_next);
> */
> void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
> {
> + struct drm_mode_config *config = &iter->dev->mode_config;
> + unsigned long flags;
> +
> iter->dev = NULL;
> - if (iter->conn)
> - drm_connector_put_safe(iter->conn);
> + if (iter->conn) {
> + spin_lock_irqsave(&config->connector_list_lock, flags);
> + __drm_connector_put_safe(iter->conn);
> + spin_unlock_irqrestore(&config->connector_list_lock, flags);
> + }
> lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
> }
> EXPORT_SYMBOL(drm_connector_list_iter_end);
> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> index 9ebb8841778c..af00f42ba269 100644
> --- a/drivers/gpu/drm/drm_crtc_internal.h
> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> @@ -142,6 +142,7 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
> uint64_t value);
> int drm_connector_create_standard_properties(struct drm_device *dev);
> const char *drm_get_connector_force_name(enum drm_connector_force force);
> +void drm_connector_free_work_fn(struct work_struct *work);
>
> /* IOCTL */
> int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
> diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
> index 6ffe952142e6..025fc23cf7c6 100644
> --- a/drivers/gpu/drm/drm_mode_config.c
> +++ b/drivers/gpu/drm/drm_mode_config.c
> @@ -373,6 +373,7 @@ void drm_mode_config_init(struct drm_device *dev)
> INIT_LIST_HEAD(&dev->mode_config.fb_list);
> INIT_LIST_HEAD(&dev->mode_config.crtc_list);
> INIT_LIST_HEAD(&dev->mode_config.connector_list);
> + INIT_LIST_HEAD(&dev->mode_config.connector_free_list);
> INIT_LIST_HEAD(&dev->mode_config.encoder_list);
> INIT_LIST_HEAD(&dev->mode_config.property_list);
> INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
> @@ -382,6 +383,8 @@ void drm_mode_config_init(struct drm_device *dev)
> ida_init(&dev->mode_config.connector_ida);
> spin_lock_init(&dev->mode_config.connector_list_lock);
>
> + INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
> +
> drm_mode_create_standard_properties(dev);
>
> /* Just to be sure */
> @@ -432,7 +435,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
> }
> drm_connector_list_iter_end(&conn_iter);
> /* connector_iter drops references in a work item. */
> - flush_scheduled_work();
> + flush_work(&dev->mode_config.connector_free_work);
> if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
> drm_connector_list_iter_begin(dev, &conn_iter);
> drm_for_each_connector_iter(connector, &conn_iter)
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index ee3155391243..50bc21050fbf 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -966,12 +966,12 @@ struct drm_connector {
> uint16_t tile_h_size, tile_v_size;
>
> /**
> - * @free_work:
> + * @free_head:
> *
> * Work used only by &drm_connector_iter to be able to clean up a
> * connector from any context.
> */
> - struct work_struct free_work;
> + struct list_head free_head;
> };
>
> #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 e5f3b43014e1..5e62e52a2c58 100644
> --- a/include/drm/drm_mode_config.h
> +++ b/include/drm/drm_mode_config.h
> @@ -402,7 +402,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;
> /**
> @@ -422,6 +422,21 @@ struct drm_mode_config {
> * &struct drm_connector_list_iter to walk this list.
> */
> 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 list_head connector_free_list;
> + /**
> + * @connector_free_work: Work to clean up @connector_free_list.
> + */
> + struct work_struct connector_free_work;
> +
> /**
> * @num_encoder:
> *
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
next prev parent reply other threads:[~2017-12-13 12:27 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20171213104607epcas4p420c1a7a83a19c1924318207c0bb2e8e2@epcas4p4.samsung.com>
2017-12-13 10:45 ` [PATCH] drm: rework delayed connector cleanup in connector_iter Daniel Vetter
2017-12-13 10:45 ` Daniel Vetter
2017-12-13 11:04 ` Chris Wilson
2017-12-13 11:04 ` Chris Wilson
2017-12-13 11:48 ` ✗ Fi.CI.BAT: failure for " Patchwork
2017-12-13 12:27 ` Marek Szyprowski [this message]
2017-12-13 12:49 ` [PATCH] " Daniel Vetter
2017-12-13 12:49 ` Daniel Vetter
2017-12-13 13:01 ` Marek Szyprowski
2017-12-13 13:05 ` Chris Wilson
2017-12-13 13:05 ` Chris Wilson
2017-12-13 13:35 ` Daniel Vetter
2017-12-13 13:35 ` Daniel Vetter
2017-12-13 21:59 ` Daniel Vetter
2017-12-13 21:59 ` Daniel Vetter
2017-12-13 14:48 ` ✓ Fi.CI.BAT: success for drm: rework delayed connector cleanup in connector_iter (rev2) Patchwork
2017-12-13 17:30 ` ✗ Fi.CI.IGT: warning " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2afb1fd9-fc9f-df1e-2a97-1071764ed9b0@samsung.com \
--to=m.szyprowski@samsung.com \
--cc=airlied@linux.ie \
--cc=ben@bwidawsk.net \
--cc=broonie@kernel.org \
--cc=daniel.vetter@ffwll.ch \
--cc=daniel.vetter@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=enric.balletbo@collabora.com \
--cc=guillaume.tucker@collabora.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=javier@dowhile0.org \
--cc=khilman@baylibre.com \
--cc=matthew.hart@linaro.org \
--cc=shuahkh@osg.samsung.com \
--cc=stable@vger.kernel.org \
--cc=thierry.escande@collabora.co.uk \
--cc=tomeu.vizoso@collabora.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.