[PATCH v3 07/12] drm/client: Move suspend/resume into DRM client callbacks

Thomas Zimmermann tzimmermann at suse.de
Mon Oct 14 07:07:53 UTC 2024


Hi

Am 08.10.24 um 23:21 schrieb Cavitt, Jonathan:
> -----Original Message-----
> From: Intel-xe <intel-xe-bounces at lists.freedesktop.org> On Behalf Of Thomas Zimmermann
> Sent: Tuesday, October 8, 2024 4:59 AM
> To: simona at ffwll.ch; airlied at gmail.com; javierm at redhat.com; jfalempe at redhat.com
> Cc: dri-devel at lists.freedesktop.org; amd-gfx at lists.freedesktop.org; intel-gfx at lists.freedesktop.org; intel-xe at lists.freedesktop.org; Thomas Zimmermann <tzimmermann at suse.de>
> Subject: [PATCH v3 07/12] drm/client: Move suspend/resume into DRM client callbacks
>> Suspend and resume is still tied to fbdev emulation. Modeset helpers
>> and several drivers call drm_fb_helper_set_suspend_unlocked() to inform
>> the fbdev client about suspend/resume events.
>>
>> To make it work with arbitrary clients, add per-client callback
>> functions for suspend and resume. Implement them for fbdev emulation
>> with the existing drm_fb_helper_set_suspend_unlocked(). Then update
>> DRM's modeset helpers to call the new interface.
>>
>> Clients that are not fbdev can now implement suspend/resume to their
>> requirements.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> Some questions below, but nothing blocking.
>
> Reviewed-by: Jonathan Cavitt <jonathan.cavitt at intel.com>

Thanks for reviewing this series.

>
>> ---
>>   drivers/gpu/drm/drm_client_event.c   | 60 ++++++++++++++++++++++++++++
>>   drivers/gpu/drm/drm_fbdev_client.c   | 30 +++++++++++++-
>>   drivers/gpu/drm/drm_modeset_helper.c | 14 ++++---
>>   include/drm/drm_client.h             | 35 ++++++++++++++++
>>   include/drm/drm_client_event.h       |  2 +
>>   5 files changed, 133 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_client_event.c b/drivers/gpu/drm/drm_client_event.c
>> index d13d44320c5c..c52e93643672 100644
>> --- a/drivers/gpu/drm/drm_client_event.c
>> +++ b/drivers/gpu/drm/drm_client_event.c
>> @@ -107,6 +107,66 @@ void drm_client_dev_restore(struct drm_device *dev)
>>   	mutex_unlock(&dev->clientlist_mutex);
>>   }
>>   
>> +static int drm_client_suspend(struct drm_client_dev *client, bool holds_console_lock)
>> +{
>> +	struct drm_device *dev = client->dev;
>> +	int ret = 0;
>> +
>> +	if (drm_WARN_ON_ONCE(dev, client->suspended))
>> +		return 0;
>> +
>> +	if (client->funcs && client->funcs->suspend)
>> +		ret = client->funcs->suspend(client, holds_console_lock);
>> +	drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
>> +
>> +	client->suspended = true;
>> +
>> +	return ret;
>> +}
>> +
>> +void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock)
>> +{
>> +	struct drm_client_dev *client;
>> +
>> +	mutex_lock(&dev->clientlist_mutex);
>> +	list_for_each_entry(client, &dev->clientlist, list) {
>> +		if (!client->suspended)
>> +			drm_client_suspend(client, holds_console_lock);
>> +	}
>> +	mutex_unlock(&dev->clientlist_mutex);
>> +}
>> +EXPORT_SYMBOL(drm_client_dev_suspend);
>> +
>> +static int drm_client_resume(struct drm_client_dev *client, bool holds_console_lock)
>> +{
>> +	struct drm_device *dev = client->dev;
>> +	int ret = 0;
>> +
>> +	if (drm_WARN_ON_ONCE(dev, !client->suspended))
>> +		return 0;
>> +
>> +	if (client->funcs && client->funcs->resume)
>> +		ret = client->funcs->resume(client, holds_console_lock);
>> +	drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
>> +
>> +	client->suspended = false;
>> +
>> +	return ret;
>> +}
>> +
>> +void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock)
>> +{
>> +	struct drm_client_dev *client;
>> +
>> +	mutex_lock(&dev->clientlist_mutex);
>> +	list_for_each_entry(client, &dev->clientlist, list) {
>> +		if  (client->suspended)
>> +			drm_client_resume(client, holds_console_lock);
>> +	}
>> +	mutex_unlock(&dev->clientlist_mutex);
>> +}
>> +EXPORT_SYMBOL(drm_client_dev_resume);
> I had to double check, as it seemed a bit weird to have a Boolean "holds_console_lock"
> if it was always going to be False in the use cases presented in this patch, but we do set
> it to True in the Radeon use case in patch 10, so that makes more sense.

I can mention this in the commit message.

>
>> +
>>   #ifdef CONFIG_DEBUG_FS
>>   static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
>>   {
>> diff --git a/drivers/gpu/drm/drm_fbdev_client.c b/drivers/gpu/drm/drm_fbdev_client.c
>> index a09382afe2fb..246fb63ab250 100644
>> --- a/drivers/gpu/drm/drm_fbdev_client.c
>> +++ b/drivers/gpu/drm/drm_fbdev_client.c
>> @@ -61,11 +61,37 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
>>   	return ret;
>>   }
>>   
>> +static int drm_fbdev_client_suspend(struct drm_client_dev *client, bool holds_console_lock)
>> +{
>> +	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
>> +
>> +	if (holds_console_lock)
>> +		drm_fb_helper_set_suspend(fb_helper, true);
>> +	else
>> +		drm_fb_helper_set_suspend_unlocked(fb_helper, true);
>> +
>> +	return 0;
>> +}
>> +
>> +static int drm_fbdev_client_resume(struct drm_client_dev *client, bool holds_console_lock)
>> +{
>> +	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
>> +
>> +	if (holds_console_lock)
>> +		drm_fb_helper_set_suspend(fb_helper, false);
>> +	else
>> +		drm_fb_helper_set_suspend_unlocked(fb_helper, false);
>> +
>> +	return 0;
>> +}
>> +
>>   static const struct drm_client_funcs drm_fbdev_client_funcs = {
>>   	.owner		= THIS_MODULE,
>>   	.unregister	= drm_fbdev_client_unregister,
>>   	.restore	= drm_fbdev_client_restore,
>>   	.hotplug	= drm_fbdev_client_hotplug,
>> +	.suspend	= drm_fbdev_client_suspend,
>> +	.resume		= drm_fbdev_client_resume,
>>   };
> Just a question for my own understanding:
>
>
> The expected order of operations here is:
>
> drm_mode_config_helper_suspend calls drm_client_dev_suspend
>
> drm_client_dev_suspend calls drm_client_suspend
>
> drm_client_suspend calls client->funcs->suspend, which for fbdev is
> drm_fbdev_client_suspend
>
> drm_fbdev_client_suspend calls drm_fb_helper_set_suspend(_unlocked)
>
> And, circling back to the start, drm_mode_config_helper_suspend is called by
> several drivers in the suspend case.
>
>
> Is this correct?

Yes, that's what's happening. This patch pushes the driver's direct call 
to drm_fb_helper_() interfaces into a callback of the client. That 
releases the module dependency and other clients can be used as well.

>
>>   
>>   /**
>> @@ -76,8 +102,8 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = {
>>    *
>>    * This function sets up fbdev emulation. Restore, hotplug events and
>>    * teardown are all taken care of. Drivers that do suspend/resume need
>> - * to call drm_fb_helper_set_suspend_unlocked() themselves. Simple
>> - * drivers might use drm_mode_config_helper_suspend().
>> + * to call drm_client_dev_suspend() and drm_client_dev_resume() by
>> + * themselves. Simple drivers might use drm_mode_config_helper_suspend().
>>    *
>>    * This function is safe to call even when there are no connectors present.
>>    * Setup will be retried on the next hotplug event.
>> diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
>> index 2c582020cb42..5565464c1734 100644
>> --- a/drivers/gpu/drm/drm_modeset_helper.c
>> +++ b/drivers/gpu/drm/drm_modeset_helper.c
>> @@ -21,7 +21,7 @@
>>    */
>>   
>>   #include <drm/drm_atomic_helper.h>
>> -#include <drm/drm_fb_helper.h>
>> +#include <drm/drm_client_event.h>
>>   #include <drm/drm_fourcc.h>
>>   #include <drm/drm_framebuffer.h>
>>   #include <drm/drm_modeset_helper.h>
>> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(drm_crtc_init);
>>    * Zero on success, negative error code on error.
>>    *
>>    * See also:
>> - * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked().
>> + * drm_kms_helper_poll_disable() and drm_client_dev_suspend().
>>    */
>>   int drm_mode_config_helper_suspend(struct drm_device *dev)
>>   {
>> @@ -199,10 +199,11 @@ int drm_mode_config_helper_suspend(struct drm_device *dev)
>>   	if (dev->mode_config.poll_enabled)
>>   		drm_kms_helper_poll_disable(dev);
>>   
>> -	drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1);
>> +	drm_client_dev_suspend(dev, false);
>>   	state = drm_atomic_helper_suspend(dev);
>>   	if (IS_ERR(state)) {
>> -		drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
>> +		drm_client_dev_resume(dev, false);
>> +
>>   		/*
>>   		 * Don't enable polling if it was never initialized
>>   		 */
>> @@ -230,7 +231,7 @@ EXPORT_SYMBOL(drm_mode_config_helper_suspend);
>>    * Zero on success, negative error code on error.
>>    *
>>    * See also:
>> - * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable().
>> + * drm_client_dev_resume() and drm_kms_helper_poll_enable().
>>    */
>>   int drm_mode_config_helper_resume(struct drm_device *dev)
>>   {
>> @@ -247,7 +248,8 @@ int drm_mode_config_helper_resume(struct drm_device *dev)
>>   		DRM_ERROR("Failed to resume (%d)\n", ret);
>>   	dev->mode_config.suspend_state = NULL;
>>   
>> -	drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
>> +	drm_client_dev_resume(dev, false);
>> +
>>   	/*
>>   	 * Don't enable polling if it is not initialized
>>   	 */
>> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
>> index dfd5afcc9463..c03c4b0f3e94 100644
>> --- a/include/drm/drm_client.h
>> +++ b/include/drm/drm_client.h
>> @@ -63,6 +63,34 @@ struct drm_client_funcs {
>>   	 * This callback is optional.
>>   	 */
>>   	int (*hotplug)(struct drm_client_dev *client);
>> +
>> +	/**
>> +	 * @suspend:
>> +	 *
>> +	 * Called when suspending the device.
>> +	 *
>> +	 * This callback is optional.
>> +	 *
>> +	 * FIXME: Some callers hold the console lock when invoking this
>> +	 *        function. This interferes with fbdev emulation, which
>> +	 *        also tries to acquire the lock. Push the console lock
>> +	 *        into the callback and remove 'holds_console_lock'.
>> +	 */
> Is there an estimated time for the fix to this FIXME?  It's out of scope
> for this series, so I won't insist on fixing it immediately, but if it's a
> "quick" fix (relatively speaking), then we should definitely try to get
> this FIXME resolved in short order.

There's no quick fix AFAICT. Radeon, i915 and xe call 
drm_fb_helper_set_suspend() from various places. These drivers always 
had their own code, so they likely need some work to make the change to 
the _unlocked() helper.

Best regards
Thomas

>
> -Jonathan Cavitt
>
>> +	int (*suspend)(struct drm_client_dev *client, bool holds_console_lock);
>> +
>> +	/**
>> +	 * @resume:
>> +	 *
>> +	 * Called when resuming the device from suspend.
>> +	 *
>> +	 * This callback is optional.
>> +	 *
>> +	 * FIXME: Some callers hold the console lock when invoking this
>> +	 *        function. This interferes with fbdev emulation, which
>> +	 *        also tries to acquire the lock. Push the console lock
>> +	 *        into the callback and remove 'holds_console_lock'.
>> +	 */
>> +	int (*resume)(struct drm_client_dev *client, bool holds_console_lock);
>>   };
>>   
>>   /**
>> @@ -107,6 +135,13 @@ struct drm_client_dev {
>>   	 */
>>   	struct drm_mode_set *modesets;
>>   
>> +	/**
>> +	 * @suspended:
>> +	 *
>> +	 * The client has been suspended.
>> +	 */
>> +	bool suspended;
>> +
>>   	/**
>>   	 * @hotplug_failed:
>>   	 *
>> diff --git a/include/drm/drm_client_event.h b/include/drm/drm_client_event.h
>> index 2c8915241120..72c97d111169 100644
>> --- a/include/drm/drm_client_event.h
>> +++ b/include/drm/drm_client_event.h
>> @@ -8,5 +8,7 @@ struct drm_device;
>>   void drm_client_dev_unregister(struct drm_device *dev);
>>   void drm_client_dev_hotplug(struct drm_device *dev);
>>   void drm_client_dev_restore(struct drm_device *dev);
>> +void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock);
>> +void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock);
>>   
>>   #endif
>> -- 
>> 2.46.0
>>
>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)



More information about the dri-devel mailing list