broadband-modem-qmi: reset all QMI/NET ports on initialization

If the daemon boots and it finds already existing modems in the
system (i.e. not hotplugged), we will attempt to reset all QMI/NET
ports, so that the state in which the ports are is a known one.

This logic allows us to cleanup any possible existing network link if
e.g. the daemon crashes and is restarted by the system.
This commit is contained in:
Aleksander Morgado
2021-03-10 10:59:22 +01:00
parent 7b20550ac0
commit 140094bb47
+157 -7
View File
@@ -9661,6 +9661,113 @@ signal_load_values (MMIfaceModemSignal *self,
signal_load_values_context_step (task);
}
/*****************************************************************************/
/* Reset data interfaces during initialization */
typedef struct {
GList *ports;
MMPort *data;
MMPortQmi *qmi;
} ResetPortsContext;
static void
reset_ports_context_free (ResetPortsContext *ctx)
{
g_assert (!ctx->data);
g_assert (!ctx->qmi);
g_list_free_full (ctx->ports, g_object_unref);
g_slice_free (ResetPortsContext, ctx);
}
static gboolean
reset_ports_finish (MMBroadbandModemQmi *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void reset_next_port (GTask *task);
static void
port_qmi_reset_ready (MMPortQmi *qmi,
GAsyncResult *res,
GTask *task)
{
MMBroadbandModemQmi *self;
ResetPortsContext *ctx;
g_autoptr(GError) error = NULL;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
if (!mm_port_qmi_reset_finish (qmi, res, &error))
mm_obj_warn (self, "couldn't reset QMI port '%s' with data interface '%s': %s",
mm_port_get_device (MM_PORT (ctx->qmi)),
mm_port_get_device (ctx->data),
error->message);
g_clear_object (&ctx->data);
g_clear_object (&ctx->qmi);
reset_next_port (task);
}
static void
reset_next_port (GTask *task)
{
MMBroadbandModemQmi *self;
ResetPortsContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
if (!ctx->ports) {
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
/* steal full data port reference from list head */
ctx->data = ctx->ports->data;
ctx->ports = g_list_delete_link (ctx->ports, ctx->ports);
ctx->qmi = mm_broadband_modem_qmi_get_port_qmi_for_data (self, ctx->data, NULL, NULL);
if (!ctx->qmi) {
mm_obj_dbg (self, "no QMI port associated to data port '%s': ignoring data interface reset",
mm_port_get_device (ctx->data));
g_clear_object (&ctx->data);
reset_next_port (task);
return;
}
mm_obj_dbg (self, "running QMI port '%s' reset with data interface '%s'",
mm_port_get_device (MM_PORT (ctx->qmi)), mm_port_get_device (ctx->data));
mm_port_qmi_reset (ctx->qmi,
ctx->data,
(GAsyncReadyCallback) port_qmi_reset_ready,
task);
}
static void
reset_ports (MMBroadbandModemQmi *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
ResetPortsContext *ctx;
task = g_task_new (self, NULL, callback, user_data);
ctx = g_slice_new0 (ResetPortsContext);
g_task_set_task_data (task, ctx, (GDestroyNotify)reset_ports_context_free);
ctx->ports = mm_base_modem_find_ports (MM_BASE_MODEM (self),
MM_PORT_SUBSYS_UNKNOWN,
MM_PORT_TYPE_NET);
reset_next_port (task);
}
/*****************************************************************************/
/* First enabling step */
@@ -9961,7 +10068,7 @@ allocate_next_client (GTask *task)
if (ctx->service_index == G_N_ELEMENTS (qmi_services)) {
GError *error = NULL;
/* Done we are, track device removal and launch parent's callback */
/* Done we are, track device removal and launch next step */
if (!track_qmi_device_removed (self, ctx->qmi, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
@@ -10028,6 +10135,54 @@ qmi_port_open_ready (MMPortQmi *qmi,
allocate_next_client (task);
}
static void
initialization_open_port (GTask *task)
{
InitializationStartedContext *ctx;
ctx = g_task_get_task_data (task);
mm_port_qmi_open (ctx->qmi,
TRUE,
NULL,
(GAsyncReadyCallback)qmi_port_open_ready,
task);
}
static void
reset_ports_ready (MMBroadbandModemQmi *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
if (!reset_ports_finish (self, res, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
initialization_open_port (task);
}
static void
initialization_reset_ports (GTask *task)
{
MMBroadbandModemQmi *self;
self = g_task_get_source_object (task);
/* reseting the data interfaces is really only needed if the device
* hasn't been hotplugged */
if (mm_base_modem_get_hotplugged (MM_BASE_MODEM (self))) {
mm_obj_dbg (self, "not running data interface reset procedure: device is hotplugged");
initialization_open_port (task);
return;
}
reset_ports (self, (GAsyncReadyCallback)reset_ports_ready, task);
}
static void
initialization_started (MMBroadbandModem *self,
GAsyncReadyCallback callback,
@@ -10066,12 +10221,7 @@ initialization_started (MMBroadbandModem *self,
return;
}
/* Now open our QMI port */
mm_port_qmi_open (ctx->qmi,
TRUE,
NULL,
(GAsyncReadyCallback)qmi_port_open_ready,
task);
initialization_reset_ports (task);
}
/*****************************************************************************/