From 3a1184785b52b98765db0503bc4306df9a47fe25 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Jun 2025 15:30:30 -0500 Subject: [PATCH 1/5] base-manager: rename manager/device shutdown to manager/device cleanup In preparation for a "terse" mode, but also because "shutdown" was kind of weird since we're not always shutting the modem down; sometimes we're just putting it in low-power mode. Signed-off-by: Dan Williams --- src/main.c | 17 +++- src/mm-base-manager.c | 180 +++++++++++++++++++++--------------------- src/mm-base-manager.h | 15 ++-- 3 files changed, 112 insertions(+), 100 deletions(-) diff --git a/src/main.c b/src/main.c index d6447c39..ea1e1342 100644 --- a/src/main.c +++ b/src/main.c @@ -64,10 +64,14 @@ sleeping_cb (MMSleepMonitor *sleep_monitor, { if (mm_context_get_test_low_power_suspend_resume ()) { mm_dbg ("removing devices and setting them in low power mode... (sleeping)"); - mm_base_manager_shutdown (manager, TRUE, TRUE, TRUE, ctx); + mm_base_manager_cleanup (manager, + MM_BASE_MANAGER_CLEANUP_DISABLE | + MM_BASE_MANAGER_CLEANUP_LOW_POWER | + MM_BASE_MANAGER_CLEANUP_REMOVE, + ctx); } else { mm_dbg ("removing devices... (sleeping)"); - mm_base_manager_shutdown (manager, FALSE, FALSE, TRUE, ctx); + mm_base_manager_cleanup (manager, MM_BASE_MANAGER_CLEANUP_REMOVE, ctx); } } @@ -84,7 +88,10 @@ sleeping_quick_cb (MMSleepMonitor *sleep_monitor, { if (mm_context_get_test_low_power_suspend_resume ()) { mm_dbg ("setting modem in low power mode... (sleeping)"); - mm_base_manager_shutdown (manager, TRUE, TRUE, FALSE, ctx); + mm_base_manager_cleanup (manager, + MM_BASE_MANAGER_CLEANUP_DISABLE | + MM_BASE_MANAGER_CLEANUP_LOW_POWER, + ctx); } else { /* Don't need to wait for anything; just suspend */ mm_dbg ("leaving modem powered... (sleeping)"); @@ -268,7 +275,9 @@ main (int argc, char *argv[]) (GCallback)shutdown_done, inner); - mm_base_manager_shutdown (manager, TRUE, FALSE, TRUE, ctx); + mm_base_manager_cleanup (manager, + MM_BASE_MANAGER_CLEANUP_DISABLE | MM_BASE_MANAGER_CLEANUP_REMOVE, + ctx); /* Wait for all modems to be disabled and removed, but don't wait * forever: if disabling the modems takes longer than 20s, just diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index f473ef2a..3308702b 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -870,48 +870,41 @@ mm_base_manager_start (MMBaseManager *self, /*****************************************************************************/ typedef enum { - DEVICE_SHUTDOWN_STEP_FIRST = 0, - DEVICE_SHUTDOWN_STEP_DISABLE, - DEVICE_SHUTDOWN_STEP_LOW_POWER, - DEVICE_SHUTDOWN_STEP_REMOVE, - DEVICE_SHUTDOWN_STEP_LAST, -} DeviceShutdownStep; + DEVICE_CLEANUP_STEP_FIRST = 0, + DEVICE_CLEANUP_STEP_DISABLE, + DEVICE_CLEANUP_STEP_LOW_POWER, + DEVICE_CLEANUP_STEP_REMOVE, + DEVICE_CLEANUP_STEP_LAST, +} DeviceCleanupStep; typedef struct { - MMBaseModem *modem; - gboolean disable; - gboolean low_power; - gboolean remove; + MMBaseModem *modem; + MMBaseManagerCleanupFlags flags; + DeviceCleanupStep step; +} DeviceCleanupContext; - DeviceShutdownStep step; -} DeviceShutdownContext; +static void device_cleanup_step (GTask *task); -static void device_shutdown_step (GTask *task); - -static DeviceShutdownContext * -device_shutdown_context_new (MMBaseModem *modem, - gboolean disable, - gboolean low_power, - gboolean remove) +static DeviceCleanupContext * +device_cleanup_context_new (MMBaseModem *modem, + MMBaseManagerCleanupFlags flags) { - DeviceShutdownContext *ctx; + DeviceCleanupContext *ctx; - ctx = g_slice_new0 (DeviceShutdownContext); + ctx = g_slice_new0 (DeviceCleanupContext); if (modem) ctx->modem = g_object_ref (modem); - ctx->step = DEVICE_SHUTDOWN_STEP_FIRST; - ctx->disable = disable; - ctx->low_power = low_power; - ctx->remove = remove; + ctx->step = DEVICE_CLEANUP_STEP_FIRST; + ctx->flags = flags; return ctx; } static void -device_shutdown_context_free (DeviceShutdownContext *ctx) +device_cleanup_context_free (DeviceCleanupContext *ctx) { g_clear_object (&ctx->modem); - g_slice_free (DeviceShutdownContext, ctx); + g_slice_free (DeviceCleanupContext, ctx); } static void @@ -919,7 +912,7 @@ modem_remove_ready (MMDevice *device, GAsyncResult *res, GTask *task) { - DeviceShutdownContext *ctx; + DeviceCleanupContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); @@ -928,15 +921,15 @@ modem_remove_ready (MMDevice *device, mm_obj_warn (device, "removing modem failed: %s", error->message); ctx->step++; - device_shutdown_step (task); + device_cleanup_step (task); } static void -shutdown_low_power_ready (MMIfaceModem *modem, - GAsyncResult *res, - GTask *task) +cleanup_low_power_ready (MMIfaceModem *modem, + GAsyncResult *res, + GTask *task) { - DeviceShutdownContext *ctx; + DeviceCleanupContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); @@ -945,15 +938,15 @@ shutdown_low_power_ready (MMIfaceModem *modem, mm_obj_info (modem, "changing to low power state failed: %s", error->message); ctx->step++; - device_shutdown_step (task); + device_cleanup_step (task); } static void -shutdown_disable_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) +cleanup_disable_ready (MMBaseModem *modem, + GAsyncResult *res, + GTask *task) { - DeviceShutdownContext *ctx; + DeviceCleanupContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); @@ -966,57 +959,64 @@ shutdown_disable_ready (MMBaseModem *modem, /* If disabling failed there's no point in trying to low-power the * modem; just remove it. */ - ctx->step = DEVICE_SHUTDOWN_STEP_REMOVE; + ctx->step = DEVICE_CLEANUP_STEP_REMOVE; } - device_shutdown_step (task); + device_cleanup_step (task); +} + +static gboolean +has_cleanup_flag (MMBaseManagerCleanupFlags flags, + MMBaseManagerCleanupFlags expected) +{ + return flags & expected; } static void -device_shutdown_step (GTask *task) +device_cleanup_step (GTask *task) { - DeviceShutdownContext *ctx; + DeviceCleanupContext *ctx; MMDevice *device; ctx = g_task_get_task_data (task); device = g_task_get_source_object (task); switch (ctx->step) { - case DEVICE_SHUTDOWN_STEP_FIRST: + case DEVICE_CLEANUP_STEP_FIRST: ctx->step++; /* fall through */ - case DEVICE_SHUTDOWN_STEP_DISABLE: - if (ctx->disable && ctx->modem) { + case DEVICE_CLEANUP_STEP_DISABLE: + if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_DISABLE)) { mm_obj_dbg (device, "disabling modem%d", mm_base_modem_get_dbus_id (ctx->modem)); mm_base_modem_disable (ctx->modem, MM_BASE_MODEM_OPERATION_LOCK_REQUIRED, MM_BASE_MODEM_OPERATION_PRIORITY_OVERRIDE, - (GAsyncReadyCallback)shutdown_disable_ready, + (GAsyncReadyCallback)cleanup_disable_ready, task); return; } ctx->step++; /* fall through */ - case DEVICE_SHUTDOWN_STEP_LOW_POWER: - if (ctx->low_power && ctx->modem) { + case DEVICE_CLEANUP_STEP_LOW_POWER: + if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER)) { mm_obj_dbg (device, "setting modem%d to low-power state", mm_base_modem_get_dbus_id (ctx->modem)); mm_iface_modem_set_power_state (MM_IFACE_MODEM (ctx->modem), MM_MODEM_POWER_STATE_LOW, - (GAsyncReadyCallback)shutdown_low_power_ready, + (GAsyncReadyCallback)cleanup_low_power_ready, task); return; } ctx->step++; /* fall through */ - case DEVICE_SHUTDOWN_STEP_REMOVE: - if (ctx->remove && ctx->modem) { + case DEVICE_CLEANUP_STEP_REMOVE: + if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_REMOVE)) { mm_obj_dbg (device, "removing modem%d", mm_base_modem_get_dbus_id (ctx->modem)); @@ -1028,8 +1028,8 @@ device_shutdown_step (GTask *task) ctx->step++; /* fall through */ - case DEVICE_SHUTDOWN_STEP_LAST: - mm_obj_dbg (device, "device shutdown complete"); + case DEVICE_CLEANUP_STEP_LAST: + mm_obj_dbg (device, "device cleanup complete"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -1046,25 +1046,25 @@ typedef struct { GSList *tasks; GSList *devices_to_remove; MMSleepContext *sleep_ctx; -} ManagerShutdownContext; +} ManagerCleanupContext; -static ManagerShutdownContext * -manager_shutdown_context_new (MMBaseManager *self, - MMSleepContext *sleep_ctx) +static ManagerCleanupContext * +manager_cleanup_context_new (MMBaseManager *self, + MMSleepContext *sleep_ctx) { - ManagerShutdownContext *ctx; + ManagerCleanupContext *ctx; - ctx = g_slice_new0 (ManagerShutdownContext); + ctx = g_slice_new0 (ManagerCleanupContext); ctx->self = g_object_ref (self); ctx->sleep_ctx = g_object_ref (sleep_ctx); return ctx; } static void -manager_shutdown_context_maybe_complete (ManagerShutdownContext *ctx, - GTask *task, - MMDevice *device, - gboolean remove) +manager_cleanup_context_maybe_complete (ManagerCleanupContext *ctx, + GTask *task, + MMDevice *device, + gboolean remove) { if (task) ctx->tasks = g_slist_remove (ctx->tasks, task); @@ -1085,50 +1085,48 @@ manager_shutdown_context_maybe_complete (ManagerShutdownContext *ctx, g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (device)); g_slist_free (ctx->devices_to_remove); - mm_obj_dbg (ctx->self, "shutdown complete"); + mm_obj_dbg (ctx->self, "cleanup complete"); mm_sleep_context_complete (ctx->sleep_ctx, NULL); g_object_unref (ctx->sleep_ctx); g_object_unref (ctx->self); - g_slice_free (ManagerShutdownContext, ctx); + g_slice_free (ManagerCleanupContext, ctx); } } static void -device_shutdown_ready (MMDevice *device, - GAsyncResult *res, - ManagerShutdownContext *ctx) +device_cleanup_ready (MMDevice *device, + GAsyncResult *res, + ManagerCleanupContext *ctx) { GTask *task; - DeviceShutdownContext *dctx; + DeviceCleanupContext *dctx; g_autoptr(GError) error = NULL; + gboolean remove; task = G_TASK (res); if (!g_task_propagate_boolean (task, &error)) { mm_obj_info (ctx->self, - "failed to shutdown device %s: %s", + "failed to cleanup device %s: %s", mm_device_get_uid (device), error->message); } dctx = g_task_get_task_data (task); - manager_shutdown_context_maybe_complete (ctx, - task, - device, - dctx->remove); + remove = has_cleanup_flag (dctx->flags, MM_BASE_MANAGER_CLEANUP_REMOVE); + manager_cleanup_context_maybe_complete (ctx, task, device, remove); } void -mm_base_manager_shutdown (MMBaseManager *self, - gboolean disable, - gboolean low_power, - gboolean remove, - MMSleepContext *sleep_ctx) +mm_base_manager_cleanup (MMBaseManager *self, + MMBaseManagerCleanupFlags flags, + MMSleepContext *sleep_ctx) { - ManagerShutdownContext *ctx; + ManagerCleanupContext *ctx; GHashTableIter iter; MMDevice *device; + gboolean disable, remove, low_power; g_return_if_fail (self != NULL); g_return_if_fail (MM_IS_BASE_MANAGER (self)); @@ -1136,6 +1134,9 @@ mm_base_manager_shutdown (MMBaseManager *self, /* Cancel all ongoing auth requests */ g_cancellable_cancel (self->priv->authp_cancellable); + disable = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_DISABLE); + low_power = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER); + remove = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_REMOVE); mm_obj_dbg (self, "manager shutting down... (%s%s%s%s%s)", disable ? "disable" : "", @@ -1144,30 +1145,27 @@ mm_base_manager_shutdown (MMBaseManager *self, (low_power && remove) ? "," : "", remove ? "remove" : ""); - ctx = manager_shutdown_context_new (self, sleep_ctx); + ctx = manager_cleanup_context_new (self, sleep_ctx); g_hash_table_iter_init (&iter, self->priv->devices); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { - DeviceShutdownContext *dctx; + DeviceCleanupContext *dctx; GTask *task; task = g_task_new (device, NULL, - (GAsyncReadyCallback)device_shutdown_ready, + (GAsyncReadyCallback)device_cleanup_ready, ctx); ctx->tasks = g_slist_append (ctx->tasks, task); - dctx = device_shutdown_context_new (mm_device_peek_modem (device), - disable, - low_power, - remove); - g_task_set_task_data (task, dctx, (GDestroyNotify)device_shutdown_context_free); + dctx = device_cleanup_context_new (mm_device_peek_modem (device), flags); + g_task_set_task_data (task, dctx, (GDestroyNotify)device_cleanup_context_free); - device_shutdown_step (task); + device_cleanup_step (task); } - /* Complete shutdown if there were no devices */ - manager_shutdown_context_maybe_complete (ctx, NULL, NULL, FALSE); + /* Complete cleanup if there were no devices */ + manager_cleanup_context_maybe_complete (ctx, NULL, NULL, FALSE); } guint32 diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h index c164b2fa..891dd908 100644 --- a/src/mm-base-manager.h +++ b/src/mm-base-manager.h @@ -72,11 +72,16 @@ MMBaseManager *mm_base_manager_new (GDBusConnection *bus, void mm_base_manager_start (MMBaseManager *manager, gboolean manual_scan); -void mm_base_manager_shutdown (MMBaseManager *manager, - gboolean disable, - gboolean power_low, - gboolean remove, - MMSleepContext *ctx); +typedef enum { + MM_BASE_MANAGER_CLEANUP_NONE = 0x0, + MM_BASE_MANAGER_CLEANUP_DISABLE = 0x1, + MM_BASE_MANAGER_CLEANUP_LOW_POWER = 0x2, + MM_BASE_MANAGER_CLEANUP_REMOVE = 0x4, +} MMBaseManagerCleanupFlags; + +void mm_base_manager_cleanup (MMBaseManager *manager, + MMBaseManagerCleanupFlags flags, + MMSleepContext *ctx); #if defined WITH_SUSPEND_RESUME void mm_base_manager_sync (MMBaseManager *manager); From d22bc4d402e9ac387d4fe4bb1eab943a2cbb7010 Mon Sep 17 00:00:00 2001 From: biemster Date: Thu, 5 Dec 2024 12:16:37 +0100 Subject: [PATCH 2/5] iface-modem: disable unsolicited 3GPP events during quick suspend/resume This introduces the "terse" mode during quick suspend/resume, right now it is used by 3GPP interface to disable unsolicited events, but in future it can be used by other interfaces as well. This prevents device to wake-up from suspend for each unsolicited while still allowing to wake up on calls or SMS messages. Signed-off-by: biemster Signed-off-by: Bhushan Shah --- src/main.c | 7 +- src/mm-base-manager.c | 53 ++++++++++-- src/mm-base-manager.h | 1 + src/mm-base-modem.c | 29 +++++++ src/mm-base-modem.h | 30 +++++-- src/mm-broadband-modem.c | 99 +++++++++++++++++++++ src/mm-iface-modem-3gpp.c | 177 ++++++++++++++++++++++++++++++++++++++ src/mm-iface-modem-3gpp.h | 7 ++ 8 files changed, 388 insertions(+), 15 deletions(-) diff --git a/src/main.c b/src/main.c index ea1e1342..7d32f667 100644 --- a/src/main.c +++ b/src/main.c @@ -93,9 +93,10 @@ sleeping_quick_cb (MMSleepMonitor *sleep_monitor, MM_BASE_MANAGER_CLEANUP_LOW_POWER, ctx); } else { - /* Don't need to wait for anything; just suspend */ - mm_dbg ("leaving modem powered... (sleeping)"); - mm_sleep_context_complete (ctx, NULL); + mm_dbg ("setting modem in terse mode... (only send important signals (call/text))"); + mm_base_manager_cleanup (manager, + MM_BASE_MANAGER_CLEANUP_TERSE, + ctx); } } diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index 3308702b..92dbc442 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -17,6 +17,8 @@ * Copyright (C) 2011 - 2016 Aleksander Morgado */ +#include "gio/gio.h" +#include "glib.h" #include #include @@ -874,6 +876,7 @@ typedef enum { DEVICE_CLEANUP_STEP_DISABLE, DEVICE_CLEANUP_STEP_LOW_POWER, DEVICE_CLEANUP_STEP_REMOVE, + DEVICE_CLEANUP_STEP_TERSE, DEVICE_CLEANUP_STEP_LAST, } DeviceCleanupStep; @@ -965,6 +968,25 @@ cleanup_disable_ready (MMBaseModem *modem, device_cleanup_step (task); } +#if defined WITH_SUSPEND_RESUME +static void +cleanup_terse_ready (MMBaseModem *modem, + GAsyncResult *res, + GTask *task) +{ + DeviceCleanupContext *ctx; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + if (!mm_base_modem_terse_finish (modem, res, &error)) + mm_obj_info (modem, "setting terse failed: %s", error->message); + + ctx->step++; + + device_cleanup_step (task); +} +#endif + static gboolean has_cleanup_flag (MMBaseManagerCleanupFlags flags, MMBaseManagerCleanupFlags expected) @@ -1028,6 +1050,24 @@ device_cleanup_step (GTask *task) ctx->step++; /* fall through */ + case DEVICE_CLEANUP_STEP_TERSE: + +#if defined WITH_SUSPEND_RESUME + if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_TERSE)) { + mm_obj_dbg(device, + "settting terse on modem%d", + mm_base_modem_get_dbus_id (ctx->modem)); + mm_base_modem_terse (ctx->modem, + MM_BASE_MODEM_OPERATION_LOCK_REQUIRED, + (GAsyncReadyCallback)cleanup_terse_ready, + task); + return; + } +#endif + + ctx->step++; + /* fall through */ + case DEVICE_CLEANUP_STEP_LAST: mm_obj_dbg (device, "device cleanup complete"); g_task_return_boolean (task, TRUE); @@ -1126,7 +1166,7 @@ mm_base_manager_cleanup (MMBaseManager *self, ManagerCleanupContext *ctx; GHashTableIter iter; MMDevice *device; - gboolean disable, remove, low_power; + gboolean disable, remove, low_power, terse; g_return_if_fail (self != NULL); g_return_if_fail (MM_IS_BASE_MANAGER (self)); @@ -1137,13 +1177,16 @@ mm_base_manager_cleanup (MMBaseManager *self, disable = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_DISABLE); low_power = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER); remove = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_REMOVE); + terse = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_TERSE); mm_obj_dbg (self, - "manager shutting down... (%s%s%s%s%s)", + "manager shutting down... (%s%s%s%s%s%s%s)", disable ? "disable" : "", - disable && (low_power || remove) ? "," : "", + disable && (low_power || remove || terse) ? "," : "", low_power ? "low-power" : "", - (low_power && remove) ? "," : "", - remove ? "remove" : ""); + low_power && (remove || terse) ? "," : "", + remove ? "remove" : "", + (remove && terse) ? "," : "", + terse ? "terse" : ""); ctx = manager_cleanup_context_new (self, sleep_ctx); diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h index 891dd908..16943299 100644 --- a/src/mm-base-manager.h +++ b/src/mm-base-manager.h @@ -77,6 +77,7 @@ typedef enum { MM_BASE_MANAGER_CLEANUP_DISABLE = 0x1, MM_BASE_MANAGER_CLEANUP_LOW_POWER = 0x2, MM_BASE_MANAGER_CLEANUP_REMOVE = 0x4, + MM_BASE_MANAGER_CLEANUP_TERSE = 0x8, } MMBaseManagerCleanupFlags; void mm_base_manager_cleanup (MMBaseManager *manager, diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c index 005bf396..668c8649 100644 --- a/src/mm-base-modem.c +++ b/src/mm-base-modem.c @@ -730,6 +730,7 @@ typedef enum { STATE_OPERATION_TYPE_DISABLE, #if defined WITH_SUSPEND_RESUME STATE_OPERATION_TYPE_SYNC, + STATE_OPERATION_TYPE_TERSE, #endif } StateOperationType; @@ -855,6 +856,12 @@ state_operation (MMBaseModem *self, ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->sync; ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->sync_finish; break; + case STATE_OPERATION_TYPE_TERSE: + operation_description = "terse"; + optional = TRUE; + ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->terse; + ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->terse_finish; + break; #endif default: g_assert_not_reached (); @@ -909,6 +916,28 @@ mm_base_modem_sync (MMBaseModem *self, user_data); } +gboolean +mm_base_modem_terse_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error) +{ + return state_operation_finish (self, res, error); +} + +void +mm_base_modem_terse (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) +{ + state_operation (self, + STATE_OPERATION_TYPE_TERSE, + operation_lock, + MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT, + callback, + user_data); +} + #endif /* WITH_SUSPEND_RESUME */ /******************************************************************************/ diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h index f053f3f5..957263bc 100644 --- a/src/mm-base-modem.h +++ b/src/mm-base-modem.h @@ -109,6 +109,15 @@ struct _MMBaseModemClass { * this method triggers a synchronization of all modem interfaces */ StateOperation sync; StateOperationFinish sync_finish; + + /* Modem terse. + * When suspending in quick suspend/resume mode, + * this method disables unsolicited events on the 3GPP interface only. + * This is enough for phones to suspend properly, but it + * might be useful to extend it to all other interfaces + * that support it as well */ + StateOperation terse; + StateOperationFinish terse_finish; #endif /* Allow plugins to subclass port object creation as needed */ @@ -298,13 +307,20 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self, GError **error); #if defined WITH_SUSPEND_RESUME -void mm_base_modem_sync (MMBaseModem *self, - MMBaseModemOperationLock operation_lock, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_base_modem_sync_finish (MMBaseModem *self, - GAsyncResult *res, - GError **error); +void mm_base_modem_sync (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_base_modem_sync_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error); +void mm_base_modem_terse (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_base_modem_terse_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error); #endif void mm_base_modem_teardown_ports (MMBaseModem *self, diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 6eb04fe2..8131e660 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -13158,6 +13158,103 @@ synchronize (MMBaseModem *self, syncing_step (task); } +typedef enum { + TERSE_STEP_FIRST, + TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP, + TERSE_STEP_LAST, +} TerseStep; + +typedef struct { + TerseStep step; +} TerseContext; + +static void terse_step (GTask *task); + +static gboolean +terse_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +iface_modem_3gpp_terse_ready (MMIfaceModem3gpp *self, + GAsyncResult *res, + GTask *task) +{ + TerseContext *ctx; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + + if (!mm_iface_modem_3gpp_terse_finish (self, res, &error)) + mm_obj_warn (self, "3GPP interface disable unsolicited events failed: %s", error->message); + + /* Go on to next step */ + ctx->step++; + terse_step (task); +} + +static void +terse_step (GTask *task) +{ + MMBroadbandModem *self; + TerseContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case TERSE_STEP_FIRST: + ctx->step++; + /* fall through */ + + case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP: + if (self->priv->modem_3gpp_dbus_skeleton && + (self->priv->modem_state >= MM_MODEM_STATE_ENABLED)) { + mm_obj_msg (self, "terse state (%d/%d): 3GPP interface disable unsolicited events", + ctx->step, TERSE_STEP_LAST); + mm_iface_modem_3gpp_terse (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_terse_ready, task); + return; + } + ctx->step++; + /* fall through */ + + case TERSE_STEP_LAST: + mm_obj_msg (self, "setting terse state (%d/%d): all done", + ctx->step, TERSE_STEP_LAST); + /* We are done without errors! */ + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + + default: + break; + } + + g_assert_not_reached (); +} + +static void +terse (MMBaseModem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TerseContext *ctx; + GTask *task; + + task = g_task_new (self, cancellable, callback, user_data); + + /* Create TerseContext */ + ctx = g_new0 (TerseContext, 1); + ctx->step = TERSE_STEP_FIRST; + g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); + + terse_step (task); +} + #endif /*****************************************************************************/ @@ -14645,6 +14742,8 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) #if defined WITH_SUSPEND_RESUME base_modem_class->sync = synchronize; base_modem_class->sync_finish = synchronize_finish; + base_modem_class->terse = terse; + base_modem_class->terse_finish = terse_finish; #endif klass->setup_ports = setup_ports; diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c index c103fd13..faaa4dfd 100644 --- a/src/mm-iface-modem-3gpp.c +++ b/src/mm-iface-modem-3gpp.c @@ -3232,6 +3232,8 @@ static void interface_syncing_step (GTask *task); typedef enum { SYNCING_STEP_FIRST, + SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS, + SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS, SYNCING_STEP_REFRESH_3GPP_REGISTRATION, SYNCING_STEP_REFRESH_EPS_BEARER, SYNCING_STEP_LAST @@ -3249,6 +3251,31 @@ mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self, return g_task_propagate_boolean (G_TASK (res), error); } +#undef VOID_SYNC_REPLY_READY_FN +#define VOID_SYNC_REPLY_READY_FN(NAME,DISPLAY) \ + static void \ + sync_##NAME##_ready (MMIfaceModem3gpp *self, \ + GAsyncResult *res, \ + GTask *task) \ + { \ + DisablingContext *ctx; \ + g_autoptr(GError) error = NULL; \ + \ + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \ + if (error) \ + mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \ + \ + /* Go on to next step */ \ + ctx = g_task_get_task_data (task); \ + ctx->step++; \ + interface_syncing_step (task); \ + } + +VOID_SYNC_REPLY_READY_FN (enable_unsolicited_events, + "enable unsolicited events") +VOID_SYNC_REPLY_READY_FN (enable_unsolicited_registration_events, + "enable unsolicited registration events") + static void sync_eps_bearer_ready (MMIfaceModem3gpp *self, GAsyncResult *res, @@ -3327,6 +3354,33 @@ interface_syncing_step (GTask *task) ctx->step++; /* fall through */ + case SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS: + if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events && + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events_finish) { + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events ( + self, + (GAsyncReadyCallback)sync_enable_unsolicited_events_ready, + task); + return; + } + ctx->step++; + /* fall through */ + + case SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS: + if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events && + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events_finish) { + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events ( + self, + get_cs_network_supported (self), + get_ps_network_supported (self), + get_eps_network_supported (self), + (GAsyncReadyCallback)sync_enable_unsolicited_registration_events_ready, + task); + return; + } + ctx->step++; + /* fall through */ + case SYNCING_STEP_REFRESH_3GPP_REGISTRATION: /* * Refresh registration info to verify that the modem is still registered. @@ -3381,6 +3435,129 @@ mm_iface_modem_3gpp_sync (MMIfaceModem3gpp *self, interface_syncing_step (task); } +typedef struct _TerseContext TerseContext; +static void interface_terse_step (GTask *task); + +typedef enum { + TERSE_STEP_FIRST, + TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS, + TERSE_STEP_DISABLE_UNSOLICITED_EVENTS, + TERSE_STEP_LAST +} TerseStep; + +struct _TerseContext { + TerseStep step; +}; + +gboolean +mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +#undef VOID_TERSE_REPLY_READY_FN +#define VOID_TERSE_REPLY_READY_FN(NAME,DISPLAY) \ + static void \ + terse_##NAME##_ready (MMIfaceModem3gpp *self, \ + GAsyncResult *res, \ + GTask *task) \ + { \ + TerseContext *ctx; \ + g_autoptr(GError) error = NULL; \ + \ + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \ + if (error) \ + mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \ + \ + /* Go on to next step */ \ + ctx = g_task_get_task_data (task); \ + ctx->step++; \ + interface_terse_step (task); \ + } + +VOID_TERSE_REPLY_READY_FN (disable_unsolicited_events, + "disable unsolicited events") +VOID_TERSE_REPLY_READY_FN (disable_unsolicited_registration_events, + "disable unsolicited registration events") + +static void +interface_terse_step (GTask *task) +{ + MMIfaceModem3gpp *self; + TerseContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case TERSE_STEP_FIRST: + ctx->step++; + /* fall through */ + + case TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS: + if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events && + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events_finish) { + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events ( + self, + get_cs_network_supported (self), + get_ps_network_supported (self), + get_eps_network_supported (self), + (GAsyncReadyCallback)terse_disable_unsolicited_registration_events_ready, + task); + mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited registration events done", + ctx->step, TERSE_STEP_LAST); + return; + } + ctx->step++; + /* fall through */ + + case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS: + if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events && + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events_finish) { + MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events ( + self, + (GAsyncReadyCallback)terse_disable_unsolicited_events_ready, + task); + mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited events done", + ctx->step, TERSE_STEP_LAST); + return; + } + ctx->step++; + /* fall through */ + + case TERSE_STEP_LAST: + /* We are done without errors! */ + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + + default: + g_assert_not_reached (); + } + + g_assert_not_reached (); +} + +void +mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TerseContext *ctx; + GTask *task; + + /* Create SyncingContext */ + ctx = g_new0 (TerseContext, 1); + ctx->step = TERSE_STEP_FIRST; + + /* Create sync steps task and execute it */ + task = g_task_new (self, NULL, callback, user_data); + g_task_set_task_data (task, ctx, (GDestroyNotify)g_free); + interface_terse_step (task); +} + #endif /*****************************************************************************/ diff --git a/src/mm-iface-modem-3gpp.h b/src/mm-iface-modem-3gpp.h index 4860e5c0..1bfc43f9 100644 --- a/src/mm-iface-modem-3gpp.h +++ b/src/mm-iface-modem-3gpp.h @@ -318,6 +318,13 @@ gboolean mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self, GAsyncResult *res, GError **error); +void mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error); + #endif /* Shutdown Modem 3GPP interface */ From b59666f48413ee0de9f6800f4fc24525d91eb9c3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Jul 2025 10:51:37 -0500 Subject: [PATCH 3/5] broadband-modem,iface-modem: move bearer counting to interface and generalize Allow counting more kinds of bearers than just multiplexed ones. Signed-off-by: Dan Williams --- src/mm-bearer-mbim.c | 9 +++--- src/mm-bearer-qmi.c | 9 +++--- src/mm-broadband-modem.c | 46 --------------------------- src/mm-broadband-modem.h | 6 ---- src/mm-iface-modem.c | 68 ++++++++++++++++++++++++++++++++++++++++ src/mm-iface-modem.h | 15 +++++++++ 6 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/mm-bearer-mbim.c b/src/mm-bearer-mbim.c index 33a1b8f1..d6bff9c8 100644 --- a/src/mm-bearer-mbim.c +++ b/src/mm-bearer-mbim.c @@ -1458,10 +1458,11 @@ load_settings_from_bearer (MMBearerMbim *self, guint max_multiplexed_bearers; const gchar *data_port_driver; - if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem), - ¤t_multiplexed_bearers, - &max_multiplexed_bearers, - error)) + if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED, + ¤t_multiplexed_bearers, + &max_multiplexed_bearers, + error)) return FALSE; /* Check multiplex support in the kernel and the device */ diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c index cccbf239..cf6c1fcf 100644 --- a/src/mm-bearer-qmi.c +++ b/src/mm-bearer-qmi.c @@ -2424,10 +2424,11 @@ load_settings_from_bearer (MMBearerQmi *self, guint max_multiplexed_bearers; gboolean multiplex_supported = TRUE; - if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem), - ¤t_multiplexed_bearers, - &max_multiplexed_bearers, - error)) + if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED, + ¤t_multiplexed_bearers, + &max_multiplexed_bearers, + error)) return FALSE; /* Check multiplex support in the kernel and the device */ diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 8131e660..c14bce3f 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -13799,52 +13799,6 @@ mm_broadband_modem_get_current_charset (MMBroadbandModem *self) /*****************************************************************************/ -static void -bearer_count_multiplexed_connected (MMBaseBearer *bearer, - guint *count) -{ - /* The Multiplexed property is only set if connected, so it's enough to check - * that one to see if we're connected and multiplexed */ - if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer))) - *count += 1; -} - -gboolean -mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self, - guint *out_current, - guint *out_max, - GError **error) -{ - g_autoptr(MMBearerList) list = NULL; - guint max; - guint count = 0; - - g_object_get (self, - MM_IFACE_MODEM_BEARER_LIST, &list, - NULL); - - if (!list) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable"); - return FALSE; - } - - max = mm_bearer_list_get_max_active_multiplexed (list); - - mm_bearer_list_foreach (list, - (MMBearerListForeachFunc)bearer_count_multiplexed_connected, - &count); - g_assert (!(!max && count)); - - if (out_max) - *out_max = max; - if (out_current) - *out_current = count; - - return TRUE; -} - -/*****************************************************************************/ - gchar * mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, const gchar *ati, diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h index f820e045..4930d4de 100644 --- a/src/mm-broadband-modem.h +++ b/src/mm-broadband-modem.h @@ -143,12 +143,6 @@ gboolean mm_broadband_modem_sim_hot_swap_ports_context_init (MMBroadbandModem GError **error); void mm_broadband_modem_sim_hot_swap_ports_context_reset (MMBroadbandModem *self); -/* Helper to manage multiplexed bearers */ -gboolean mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self, - guint *out_current, - guint *out_max, - GError **error); - /* Helper to manage initial EPS bearer */ gint mm_broadband_modem_get_initial_eps_bearer_cid (MMBroadbandModem *self); diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index de25296b..d9b2e007 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -6720,6 +6720,74 @@ mm_iface_modem_get_current_modes (MMIfaceModem *self, /*****************************************************************************/ +typedef struct { + const MMIfaceModemCountBearersFlags flags; + guint count; +} CountBearersContext; + +static void +bearer_count (MMBaseBearer *bearer, + CountBearersContext *ctx) +{ + MMBearerStatus status; + + status = mm_base_bearer_get_status (MM_BASE_BEARER (bearer)); + + if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED) { + /* The Multiplexed property is only set if connected, so it's enough to check + * that one to see if we're connected and multiplexed */ + if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer))) + ctx->count++; + } else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED) { + if (status == MM_BEARER_STATUS_CONNECTED) + ctx->count++; + } else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE) { + if (status >= MM_BEARER_STATUS_CONNECTING) + ctx->count++; + } else + ctx->count++; +} + +gboolean +mm_iface_modem_count_bearers (MMIfaceModem *self, + MMIfaceModemCountBearersFlags flags, + guint *out_current, + guint *out_max, + GError **error) +{ + g_autoptr(MMBearerList) list = NULL; + guint max = 0; + CountBearersContext ctx = { + .flags = flags, + .count = 0, + }; + + g_object_get (self, + MM_IFACE_MODEM_BEARER_LIST, &list, + NULL); + if (!list) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable"); + return FALSE; + } + + if (flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED) + max = mm_bearer_list_get_max_active_multiplexed (list); + else + max = mm_bearer_list_get_max_active (list); + + mm_bearer_list_foreach (list, (MMBearerListForeachFunc)bearer_count, &ctx); + g_assert (max >= ctx.count); + + if (out_max) + *out_max = max; + if (out_current) + *out_current = ctx.count; + + return TRUE; +} + +/*****************************************************************************/ + static void mm_iface_modem_default_init (MMIfaceModemInterface *iface) { diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h index 18c7e9ea..977dd16c 100644 --- a/src/mm-iface-modem.h +++ b/src/mm-iface-modem.h @@ -620,4 +620,19 @@ void mm_iface_modem_modify_sim (MMIfaceModem *self, void mm_iface_modem_process_sim_event (MMIfaceModem *self); +typedef enum { + /* Connecting or connected bearers */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE = 0x1, + /* Fully connected bearers */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED = 0x2, + /* Multiplexed implies connected */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED = 0x4, +} MMIfaceModemCountBearersFlags; + +gboolean mm_iface_modem_count_bearers (MMIfaceModem *self, + MMIfaceModemCountBearersFlags flags, + guint *out_current, + guint *out_max, + GError **error); + #endif /* MM_IFACE_MODEM_H */ From e867a49d928b308dc9d1afe059e63f3dd85a125b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 6 Jul 2025 18:15:19 -0500 Subject: [PATCH 4/5] sleep-context: add ability to increase timeout Track when the timeout was started, so that if it needs to be increased we can calculate how long the new timeout should be. Then cancel the original timeout and start a new one with. Signed-off-by: Dan Williams --- src/mm-sleep-context.c | 33 ++++++++++++++++++++++++++++++--- src/mm-sleep-context.h | 3 +++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/mm-sleep-context.c b/src/mm-sleep-context.c index 69a9da22..d6c01198 100644 --- a/src/mm-sleep-context.c +++ b/src/mm-sleep-context.c @@ -27,6 +27,7 @@ G_DEFINE_TYPE_EXTENDED (MMSleepContext, mm_sleep_context, G_TYPE_OBJECT, 0, struct _MMSleepContextPrivate { GTask *task; guint timeout_id; + gint64 timeout_start; }; enum { @@ -52,6 +53,7 @@ timeout_cleanup (MMSleepContext *self) if (self->priv->timeout_id) g_source_remove (self->priv->timeout_id); self->priv->timeout_id = 0; + self->priv->timeout_start = 0; } void @@ -95,6 +97,33 @@ operation_ready (MMSleepContext *self, g_signal_emit (self, signals[DONE], 0, error); } +static void +timeout_add (MMSleepContext *self, + guint interval) +{ + timeout_cleanup (self); + self->priv->timeout_start = g_get_monotonic_time (); + self->priv->timeout_id = g_timeout_add_seconds (interval, + (GSourceFunc)operation_timeout, + self); +} + +void +mm_sleep_context_timeout_backoff (MMSleepContext *self, + guint more_seconds) +{ + gint64 cur_time; + gint64 new_interval; + + new_interval = more_seconds * G_USEC_PER_SEC; + if (self->priv->timeout_start) { + cur_time = g_get_monotonic_time (); + new_interval += (cur_time - self->priv->timeout_start); + } + + timeout_add (self, new_interval / G_USEC_PER_SEC); +} + /*****************************************************************************/ MMSleepContext * @@ -107,9 +136,7 @@ mm_sleep_context_new (guint timeout_seconds) NULL, (GAsyncReadyCallback)operation_ready, NULL); - self->priv->timeout_id = g_timeout_add_seconds (timeout_seconds, - (GSourceFunc)operation_timeout, - self); + timeout_add (self, timeout_seconds); mm_obj_dbg (self, "new context with %d second timeout", timeout_seconds); return self; diff --git a/src/mm-sleep-context.h b/src/mm-sleep-context.h index cd45c1f2..44b3c28a 100644 --- a/src/mm-sleep-context.h +++ b/src/mm-sleep-context.h @@ -51,6 +51,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSleepContext, g_object_unref) MMSleepContext *mm_sleep_context_new (guint timeout_seconds); +void mm_sleep_context_timeout_backoff (MMSleepContext *self, + guint more_seconds); + /* The MMSleepContext assumes ownership of @error */ void mm_sleep_context_complete (MMSleepContext *self, GError *error); From 79d495c892c15acb3bb7f57a2161383244b421a0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Jul 2025 10:52:29 -0500 Subject: [PATCH 5/5] base-manager: increase suspend timeout for each active bearer Some modems can take a very long time (~20s) to reply to bearer disconnect requests especially in marginal signal situations where the modem must resend messages to the network after internal timeouts. Give the modem a chance to suspend successfully if there are active bearers. Related: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1311#note_2938638 Signed-off-by: Dan Williams --- src/mm-base-manager.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index 92dbc442..84c450e4 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -1167,6 +1167,7 @@ mm_base_manager_cleanup (MMBaseManager *self, GHashTableIter iter; MMDevice *device; gboolean disable, remove, low_power, terse; + guint active_bearers = 0; g_return_if_fail (self != NULL); g_return_if_fail (MM_IS_BASE_MANAGER (self)); @@ -1193,7 +1194,20 @@ mm_base_manager_cleanup (MMBaseManager *self, g_hash_table_iter_init (&iter, self->priv->devices); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { DeviceCleanupContext *dctx; - GTask *task; + GTask *task; + MMBaseModem *modem; + + modem = mm_device_peek_modem (device); + if (modem) { + guint count = 0; + + mm_iface_modem_count_bearers (MM_IFACE_MODEM (modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE, + &count, + NULL, + NULL); + active_bearers += count; + } task = g_task_new (device, NULL, @@ -1201,12 +1215,18 @@ mm_base_manager_cleanup (MMBaseManager *self, ctx); ctx->tasks = g_slist_append (ctx->tasks, task); - dctx = device_cleanup_context_new (mm_device_peek_modem (device), flags); + dctx = device_cleanup_context_new (modem, flags); g_task_set_task_data (task, dctx, (GDestroyNotify)device_cleanup_context_free); device_cleanup_step (task); } + /* Increase cleanup timeout for each connected bearer; disconnecting a + * bearer can take many seconds. + */ + if (active_bearers) + mm_sleep_context_timeout_backoff (sleep_ctx, active_bearers * 20); + /* Complete cleanup if there were no devices */ manager_cleanup_context_maybe_complete (ctx, NULL, NULL, FALSE); }