aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-port-qmi.c188
1 files changed, 120 insertions, 68 deletions
diff --git a/src/mm-port-qmi.c b/src/mm-port-qmi.c
index 2c608e96..f3c64464 100644
--- a/src/mm-port-qmi.c
+++ b/src/mm-port-qmi.c
@@ -29,8 +29,6 @@
#include "mm-modem-helpers-qmi.h"
#include "mm-log-object.h"
-#define DEFAULT_LINK_PREALLOCATED_AMOUNT 4
-
/* as internally defined in the kernel */
#define RMNET_MAX_PACKET_SIZE 16384
#define MHI_NET_MTU_DEFAULT 16384
@@ -61,6 +59,7 @@ struct _MMPortQmiPrivate {
GList *services;
gchar *net_driver;
gchar *net_sysfs_path;
+ guint net_preallocated_links_requested;
#if defined WITH_QRTR
QrtrNode *node;
#endif
@@ -79,6 +78,7 @@ struct _MMPortQmiPrivate {
QmiWdaDataAggregationProtocol dap;
guint max_multiplexed_links;
/* preallocated links */
+ guint preallocated_links_needed;
MMPort *preallocated_links_main;
GArray *preallocated_links;
GList *preallocated_links_setup_pending;
@@ -485,9 +485,11 @@ acquire_preallocated_link (MMPortQmi *self,
/*****************************************************************************/
typedef struct {
- QmiDevice *qmi_device;
- MMPort *data;
- GArray *preallocated_links;
+ QmiDevice *qmi_device;
+ gchar *link_prefix_hint;
+ QmiDeviceAddLinkFlags flags;
+ MMPort *data;
+ GArray *preallocated_links;
} InitializePreallocatedLinksContext;
static void
@@ -497,6 +499,7 @@ initialize_preallocated_links_context_free (InitializePreallocatedLinksContext *
delete_preallocated_links (ctx->qmi_device, ctx->preallocated_links);
g_array_unref (ctx->preallocated_links);
}
+ g_clear_pointer (&ctx->link_prefix_hint, g_free);
g_object_unref (ctx->qmi_device);
g_object_unref (ctx->data);
g_slice_free (InitializePreallocatedLinksContext, ctx);
@@ -517,16 +520,18 @@ device_add_link_preallocated_ready (QmiDevice *device,
GAsyncResult *res,
GTask *task)
{
+ MMPortQmi *self;
InitializePreallocatedLinksContext *ctx;
GError *error = NULL;
PreallocatedLinkInfo info = { NULL, 0, FALSE };
- ctx = g_task_get_task_data (task);
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
- info.link_name = qmi_device_add_link_finish (device, res, &info.mux_id, &error);
+ info.link_name = qmi_device_add_link_with_flags_finish (device, res, &info.mux_id, &error);
if (!info.link_name) {
g_prefix_error (&error, "failed to add preallocated link (%u/%u) for device: ",
- ctx->preallocated_links->len + 1, DEFAULT_LINK_PREALLOCATED_AMOUNT);
+ ctx->preallocated_links->len + 1, self->priv->preallocated_links_needed);
g_task_return_error (task, error);
return;
}
@@ -551,25 +556,29 @@ initialize_preallocated_links_next (GTask *task)
return;
}
- if (ctx->preallocated_links->len == DEFAULT_LINK_PREALLOCATED_AMOUNT) {
+ g_assert (self->priv->preallocated_links_needed > 0);
+ if (ctx->preallocated_links->len == (guint) self->priv->preallocated_links_needed) {
g_task_return_pointer (task, g_steal_pointer (&ctx->preallocated_links), (GDestroyNotify)g_array_unref);
g_object_unref (task);
return;
}
- qmi_device_add_link (self->priv->qmi_device,
- ctx->preallocated_links->len + 1,
- mm_kernel_device_get_name (mm_port_peek_kernel_device (ctx->data)),
- "ignored", /* n/a in qmi_wwan add_mux */
- NULL,
- (GAsyncReadyCallback) device_add_link_preallocated_ready,
- task);
+ qmi_device_add_link_with_flags (self->priv->qmi_device,
+ ctx->preallocated_links->len + 1,
+ mm_kernel_device_get_name (mm_port_peek_kernel_device (ctx->data)),
+ ctx->link_prefix_hint,
+ ctx->flags,
+ NULL,
+ (GAsyncReadyCallback) device_add_link_preallocated_ready,
+ task);
}
static void
-initialize_preallocated_links (MMPortQmi *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+initialize_preallocated_links (MMPortQmi *self,
+ const gchar *link_prefix_hint,
+ QmiDeviceAddLinkFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
InitializePreallocatedLinksContext *ctx;
GTask *task;
@@ -578,8 +587,10 @@ initialize_preallocated_links (MMPortQmi *self,
ctx = g_slice_new0 (InitializePreallocatedLinksContext);
ctx->qmi_device = g_object_ref (self->priv->qmi_device);
+ ctx->link_prefix_hint = g_strdup (link_prefix_hint);
+ ctx->flags = flags;
ctx->data = g_object_ref (self->priv->preallocated_links_main);
- ctx->preallocated_links = g_array_sized_new (FALSE, FALSE, sizeof (PreallocatedLinkInfo), DEFAULT_LINK_PREALLOCATED_AMOUNT);
+ ctx->preallocated_links = g_array_sized_new (FALSE, FALSE, sizeof (PreallocatedLinkInfo), self->priv->preallocated_links_needed);
g_array_set_clear_func (ctx->preallocated_links, (GDestroyNotify)preallocated_link_info_clear);
g_task_set_task_data (task, ctx, (GDestroyNotify)initialize_preallocated_links_context_free);
@@ -771,21 +782,8 @@ mm_port_qmi_setup_link (MMPortQmi *self,
ctx->mux_id = QMI_DEVICE_MUX_ID_UNBOUND;
g_task_set_task_data (task, ctx, (GDestroyNotify) setup_link_context_free);
- /* When using rmnet, just try to add link in the QmiDevice */
- if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) {
- qmi_device_add_link_with_flags (self->priv->qmi_device,
- QMI_DEVICE_MUX_ID_AUTOMATIC,
- mm_kernel_device_get_name (mm_port_peek_kernel_device (data)),
- link_prefix_hint,
- get_rmnet_device_add_link_flags (self),
- NULL,
- (GAsyncReadyCallback) device_add_link_ready,
- task);
- return;
- }
-
- /* For qmi_wwan, use preallocated links */
- if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) {
+ /* If we're requested to use preallocated links, do it right away */
+ if (self->priv->preallocated_links_needed > 0) {
if (self->priv->preallocated_links) {
setup_preallocated_link (task);
return;
@@ -803,11 +801,26 @@ mm_port_qmi_setup_link (MMPortQmi *self,
/* Store main to flag that we're initializing preallocated links */
self->priv->preallocated_links_main = g_object_ref (data);
initialize_preallocated_links (self,
+ link_prefix_hint,
+ get_rmnet_device_add_link_flags (self),
(GAsyncReadyCallback) initialize_preallocated_links_ready,
task);
return;
}
+ /* No preallocated links required and using rmnet, just try to add link in the QmiDevice */
+ if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) {
+ qmi_device_add_link_with_flags (self->priv->qmi_device,
+ QMI_DEVICE_MUX_ID_AUTOMATIC,
+ mm_kernel_device_get_name (mm_port_peek_kernel_device (data)),
+ link_prefix_hint,
+ get_rmnet_device_add_link_flags (self),
+ NULL,
+ (GAsyncReadyCallback) device_add_link_ready,
+ task);
+ return;
+ }
+
g_assert_not_reached ();
}
@@ -865,7 +878,17 @@ mm_port_qmi_cleanup_link (MMPortQmi *self,
return;
}
- /* When using rmnet, just try to add link in the QmiDevice */
+ /* If using preallocated links, just release one */
+ if (self->priv->preallocated_links_needed > 0) {
+ if (!release_preallocated_link (self, link_name, mux_id, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* When using rmnet, just try to delete the link from the QmiDevice */
if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) {
qmi_device_delete_link (self->priv->qmi_device,
link_name,
@@ -876,16 +899,6 @@ mm_port_qmi_cleanup_link (MMPortQmi *self,
return;
}
- /* For qmi_wwan, use preallocated links */
- if (self->priv->kernel_data_modes & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) {
- if (!release_preallocated_link (self, link_name, mux_id, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
g_assert_not_reached ();
}
@@ -1213,6 +1226,7 @@ load_supported_kernel_data_modes (MMPortQmi *self,
/*****************************************************************************/
+#define DEFAULT_QMI_WWAN_PREALLOCATED_LINKS 4
#define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_SIZE 32768
#define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_SIZE_QMI_WWAN_RMNET 16384
#define DEFAULT_DOWNLINK_DATA_AGGREGATION_MAX_DATAGRAMS 32
@@ -1300,6 +1314,57 @@ internal_setup_data_format_context_free (InternalSetupDataFormatContext *ctx)
g_slice_free (InternalSetupDataFormatContext, ctx);
}
+static void
+internal_setup_data_format_propagate_link_setup (GTask *task,
+ guint *out_max_multiplexed_links,
+ guint *out_preallocated_links)
+{
+ MMPortQmi *self;
+ InternalSetupDataFormatContext *ctx;
+ guint max_multiplexed_links;
+ guint preallocated_links;
+
+ if (!out_max_multiplexed_links && !out_preallocated_links)
+ return;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ if (!ctx->wda_dap_supported) {
+ max_multiplexed_links = 0;
+ preallocated_links = 0;
+ mm_obj_dbg (self, "wda data aggregation protocol unsupported: no multiplexed bearers allowed");
+ } else {
+ /* if multiplex backend may be rmnet, MAX-MIN */
+ if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) {
+ max_multiplexed_links = 1 + (QMI_DEVICE_MUX_ID_MAX - QMI_DEVICE_MUX_ID_MIN);
+ preallocated_links = (self->priv->net_preallocated_links_requested > max_multiplexed_links) ?
+ max_multiplexed_links :
+ self->priv->net_preallocated_links_requested;
+ mm_obj_dbg (self, "rmnet link management supported: %u multiplexed bearers allowed, %u links preallocated",
+ max_multiplexed_links, preallocated_links);
+ }
+ /* if multiplex backend may be qmi_wwan, the max preallocated amount :/ */
+ else if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) {
+ preallocated_links = (self->priv->net_preallocated_links_requested > 0) ?
+ self->priv->net_preallocated_links_requested :
+ DEFAULT_QMI_WWAN_PREALLOCATED_LINKS;
+ max_multiplexed_links = preallocated_links;
+ mm_obj_dbg (self, "qmi_wwan link management supported: %u multiplexed bearers allowed, %u links preallocated",
+ max_multiplexed_links, preallocated_links);
+ } else {
+ max_multiplexed_links = 0;
+ preallocated_links = 0;
+ mm_obj_dbg (self, "link management unsupported: no multiplexed bearers allowed");
+ }
+ }
+
+ if (out_max_multiplexed_links)
+ *out_max_multiplexed_links = max_multiplexed_links;
+ if (out_preallocated_links)
+ *out_preallocated_links = preallocated_links;
+}
+
static gboolean
internal_setup_data_format_finish (MMPortQmi *self,
GAsyncResult *res,
@@ -1307,6 +1372,7 @@ internal_setup_data_format_finish (MMPortQmi *self,
QmiWdaLinkLayerProtocol *out_llp,
QmiWdaDataAggregationProtocol *out_dap,
guint *out_max_multiplexed_links,
+ guint *out_preallocated_links,
GError **error)
{
InternalSetupDataFormatContext *ctx;
@@ -1320,28 +1386,9 @@ internal_setup_data_format_finish (MMPortQmi *self,
g_assert (ctx->wda_dl_dap_current == ctx->wda_ul_dap_current);
*out_dap = ctx->wda_dl_dap_current;
- if (out_max_multiplexed_links) {
- if (!ctx->wda_dap_supported) {
- *out_max_multiplexed_links = 0;
- mm_obj_dbg (self, "wda data aggregation protocol unsupported: no multiplexed bearers allowed");
- } else {
- /* if multiplex backend may be rmnet, MAX-MIN */
- if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_RMNET) {
- *out_max_multiplexed_links = 1 + (QMI_DEVICE_MUX_ID_MAX - QMI_DEVICE_MUX_ID_MIN);
- mm_obj_dbg (self, "rmnet link management supported: %u multiplexed bearers allowed",
- *out_max_multiplexed_links);
- }
- /* if multiplex backend may be qmi_wwan, the max preallocated amount :/ */
- else if (ctx->kernel_data_modes_supported & MM_PORT_QMI_KERNEL_DATA_MODE_MUX_QMIWWAN) {
- *out_max_multiplexed_links = DEFAULT_LINK_PREALLOCATED_AMOUNT;
- mm_obj_dbg (self, "qmi_wwan link management supported: %u multiplexed bearers allowed",
- *out_max_multiplexed_links);
- } else {
- *out_max_multiplexed_links = 0;
- mm_obj_dbg (self, "link management unsupported: no multiplexed bearers allowed");
- }
- }
- }
+ internal_setup_data_format_propagate_link_setup (G_TASK (res),
+ out_max_multiplexed_links,
+ out_preallocated_links);
return TRUE;
}
@@ -2076,6 +2123,7 @@ internal_setup_data_format_ready (MMPortQmi *self,
&self->priv->llp,
&self->priv->dap,
NULL, /* not expected to update */
+ NULL, /* not expected to update */
&error))
g_task_return_error (task, error);
else {
@@ -2375,6 +2423,7 @@ open_internal_setup_data_format_ready (MMPortQmi *self,
&self->priv->llp,
&self->priv->dap,
&self->priv->max_multiplexed_links,
+ &self->priv->preallocated_links_needed,
&error)) {
/* Continue with fallback to LLP requested via CTL */
mm_obj_warn (self, "Couldn't setup data format: %s", error->message);
@@ -2671,6 +2720,9 @@ mm_port_qmi_set_net_details (MMPortQmi *self,
g_assert (!self->priv->net_sysfs_path);
self->priv->net_sysfs_path = g_strdup (mm_kernel_device_get_sysfs_path (first_net_dev));
+ g_assert (!self->priv->net_preallocated_links_requested);
+ self->priv->net_preallocated_links_requested = mm_kernel_device_get_global_property_as_int (first_net_dev, "ID_MM_QMI_PREALLOCATED_LINKS");
+
initialize_endpoint_info (self);
}