base-manager: new '--test-low-power-suspend-resume' option

Will request to put the modems in low power mode upon system suspend.

Based on an earlier approach from Jack Song and Nero Zhang, see
https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1050
This commit is contained in:
Aleksander Morgado
2023-12-12 11:22:30 +00:00
committed by Aleksander Morgado
parent 63dd4ad263
commit bbd11cda4b
5 changed files with 104 additions and 26 deletions
+10 -5
View File
@@ -61,8 +61,13 @@ quit_cb (gpointer user_data)
static void static void
sleeping_cb (MMSleepMonitor *sleep_monitor) sleeping_cb (MMSleepMonitor *sleep_monitor)
{ {
mm_dbg ("removing devices... (sleeping)"); if (mm_context_get_test_low_power_suspend_resume ()) {
mm_base_manager_shutdown (manager, FALSE); mm_dbg ("removing devices and setting them in low power mode... (sleeping)");
mm_base_manager_shutdown (manager, TRUE, TRUE);
} else {
mm_dbg ("removing devices... (sleeping)");
mm_base_manager_shutdown (manager, FALSE, FALSE);
}
} }
static void static void
@@ -201,9 +206,9 @@ main (int argc, char *argv[])
{ {
MMSleepMonitor *sleep_monitor; MMSleepMonitor *sleep_monitor;
if (mm_context_get_test_no_suspend_resume()) if (mm_context_get_test_no_suspend_resume ())
mm_dbg ("Suspend/resume support disabled at runtime"); mm_dbg ("Suspend/resume support disabled at runtime");
else if (mm_context_get_test_quick_suspend_resume()) { else if (mm_context_get_test_quick_suspend_resume ()) {
mm_dbg ("Quick suspend/resume hooks enabled"); mm_dbg ("Quick suspend/resume hooks enabled");
sleep_monitor = mm_sleep_monitor_get (); sleep_monitor = mm_sleep_monitor_get ();
g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_quick_cb), NULL); g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_quick_cb), NULL);
@@ -228,7 +233,7 @@ main (int argc, char *argv[])
if (manager) { if (manager) {
GTimer *timer; GTimer *timer;
mm_base_manager_shutdown (manager, TRUE); mm_base_manager_shutdown (manager, TRUE, FALSE);
/* Wait for all modems to be disabled and removed, but don't wait /* Wait for all modems to be disabled and removed, but don't wait
* forever: if disabling the modems takes longer than 20s, just * forever: if disabling the modems takes longer than 20s, just
+76 -18
View File
@@ -57,6 +57,7 @@
#include "mm-filter.h" #include "mm-filter.h"
#include "mm-log-object.h" #include "mm-log-object.h"
#include "mm-base-modem.h" #include "mm-base-modem.h"
#include "mm-iface-modem.h"
static void initable_iface_init (GInitableIface *iface); static void initable_iface_init (GInitableIface *iface);
static void log_object_iface_init (MMLogObjectInterface *iface); static void log_object_iface_init (MMLogObjectInterface *iface);
@@ -652,39 +653,91 @@ mm_base_manager_start (MMBaseManager *self,
/*****************************************************************************/ /*****************************************************************************/
typedef struct {
MMBaseManager *self;
gboolean low_power;
} DisableContext;
static void static void
remove_disable_ready (MMBaseModem *modem, disable_context_free (DisableContext *ctx)
GAsyncResult *res, {
MMBaseManager *self) g_object_unref (ctx->self);
g_slice_free (DisableContext, ctx);
}
static void
remove_device_after_disable (MMBaseModem *modem,
DisableContext *ctx)
{ {
MMDevice *device; MMDevice *device;
/* We don't care about errors disabling at this point */ device = find_device_by_modem (ctx->self, modem);
mm_base_modem_disable_finish (modem, res, NULL);
device = find_device_by_modem (self, modem);
if (device) { if (device) {
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem)); g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
mm_device_remove_modem (device); mm_device_remove_modem (device);
g_hash_table_remove (self->priv->devices, mm_device_get_uid (device)); g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (device));
} }
disable_context_free (ctx);
} }
static void static void
foreach_disable (gpointer key, shutdown_low_power_ready (MMIfaceModem *modem,
MMDevice *device, GAsyncResult *res,
MMBaseManager *self) DisableContext *ctx)
{ {
MMBaseModem *modem; g_autoptr(GError) error = NULL;
if (!mm_iface_modem_set_power_state_finish (modem, res, &error))
mm_obj_info (ctx->self, "changing to low power state failed: %s", error->message);
remove_device_after_disable (MM_BASE_MODEM (modem), ctx);
}
static void
shutdown_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
DisableContext *ctx)
{
g_autoptr(GError) error = NULL;
/* We don't care about errors disabling at this point */
if (!mm_base_modem_disable_finish (modem, res, &error)) {
mm_obj_info (ctx->self, "disabling modem failed: %s", error->message);
}
/* Bring the modem to low power mode if requested */
else if (ctx->low_power) {
mm_iface_modem_set_power_state (MM_IFACE_MODEM (modem),
MM_MODEM_POWER_STATE_LOW,
(GAsyncReadyCallback)shutdown_low_power_ready,
ctx);
return;
}
remove_device_after_disable (modem, ctx);
}
static void
foreach_disable (gpointer key,
MMDevice *device,
DisableContext *foreach_ctx)
{
MMBaseModem *modem;
DisableContext *ctx;
modem = mm_device_peek_modem (device); modem = mm_device_peek_modem (device);
if (modem) if (!modem)
mm_base_modem_disable (modem, (GAsyncReadyCallback)remove_disable_ready, self); return;
ctx = g_slice_new0 (DisableContext);
ctx->self = g_object_ref (foreach_ctx->self);
ctx->low_power = foreach_ctx->low_power;
mm_base_modem_disable (modem, (GAsyncReadyCallback)shutdown_disable_ready, ctx);
} }
static gboolean static gboolean
foreach_remove (gpointer key, foreach_remove (gpointer key,
MMDevice *device, MMDevice *device,
MMBaseManager *self) MMBaseManager *self)
{ {
MMBaseModem *modem; MMBaseModem *modem;
@@ -698,7 +751,8 @@ foreach_remove (gpointer key,
void void
mm_base_manager_shutdown (MMBaseManager *self, mm_base_manager_shutdown (MMBaseManager *self,
gboolean disable) gboolean disable,
gboolean low_power)
{ {
g_return_if_fail (self != NULL); g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_BASE_MANAGER (self)); g_return_if_fail (MM_IS_BASE_MANAGER (self));
@@ -707,7 +761,11 @@ mm_base_manager_shutdown (MMBaseManager *self,
g_cancellable_cancel (self->priv->authp_cancellable); g_cancellable_cancel (self->priv->authp_cancellable);
if (disable) { if (disable) {
g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, self); DisableContext foreach_ctx = {
.self = self,
.low_power = low_power,
};
g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, &foreach_ctx);
/* Disabling may take a few iterations of the mainloop, so the caller /* Disabling may take a few iterations of the mainloop, so the caller
* has to iterate the mainloop until all devices have been disabled and * has to iterate the mainloop until all devices have been disabled and
+2 -1
View File
@@ -72,7 +72,8 @@ void mm_base_manager_start (MMBaseManager *manager,
gboolean manual_scan); gboolean manual_scan);
void mm_base_manager_shutdown (MMBaseManager *manager, void mm_base_manager_shutdown (MMBaseManager *manager,
gboolean disable); gboolean disable,
gboolean power_low);
#if defined WITH_SUSPEND_RESUME #if defined WITH_SUSPEND_RESUME
void mm_base_manager_sync (MMBaseManager *manager); void mm_base_manager_sync (MMBaseManager *manager);
+13
View File
@@ -238,6 +238,7 @@ static gboolean test_no_udev;
#if defined WITH_SUSPEND_RESUME #if defined WITH_SUSPEND_RESUME
static gboolean test_no_suspend_resume; static gboolean test_no_suspend_resume;
static gboolean test_quick_suspend_resume; static gboolean test_quick_suspend_resume;
static gboolean test_low_power_suspend_resume;
#endif #endif
#if defined WITH_QRTR #if defined WITH_QRTR
static gboolean test_no_qrtr; static gboolean test_no_qrtr;
@@ -285,6 +286,11 @@ static const GOptionEntry test_entries[] = {
"Enable quick suspend/resume support for modems which stay on during host suspension", "Enable quick suspend/resume support for modems which stay on during host suspension",
NULL NULL
}, },
{
"test-low-power-suspend-resume", 0, 0, G_OPTION_ARG_NONE, &test_low_power_suspend_resume,
"Enable support to put the modem in low power mode during suspend/resume",
NULL
},
#endif #endif
#if defined WITH_QRTR #if defined WITH_QRTR
{ {
@@ -358,11 +364,18 @@ mm_context_get_test_no_suspend_resume (void)
{ {
return test_no_suspend_resume; return test_no_suspend_resume;
} }
gboolean gboolean
mm_context_get_test_quick_suspend_resume (void) mm_context_get_test_quick_suspend_resume (void)
{ {
return test_quick_suspend_resume; return test_quick_suspend_resume;
} }
gboolean
mm_context_get_test_low_power_suspend_resume (void)
{
return test_low_power_suspend_resume;
}
#endif #endif
#if defined WITH_QRTR #if defined WITH_QRTR
+3 -2
View File
@@ -55,8 +55,9 @@ const gchar *mm_context_get_test_plugin_dir (void);
gboolean mm_context_get_test_no_udev (void); gboolean mm_context_get_test_no_udev (void);
#endif #endif
#if defined WITH_SUSPEND_RESUME #if defined WITH_SUSPEND_RESUME
gboolean mm_context_get_test_no_suspend_resume (void); gboolean mm_context_get_test_no_suspend_resume (void);
gboolean mm_context_get_test_quick_suspend_resume (void); gboolean mm_context_get_test_quick_suspend_resume (void);
gboolean mm_context_get_test_low_power_suspend_resume (void);
#endif #endif
#if defined WITH_QRTR #if defined WITH_QRTR
gboolean mm_context_get_test_no_qrtr (void); gboolean mm_context_get_test_no_qrtr (void);