aboutsummaryrefslogtreecommitdiff
path: root/src/mm-port-qmi.c
diff options
context:
space:
mode:
authorJoel Selvaraj <jo@jsfamily.in>2021-07-21 12:55:48 +0530
committerJoel Selvaraj <jo@jsfamily.in>2021-07-21 20:40:42 +0530
commit95f4a232cefe76b4bfc664f8dc37e68471c4a77a (patch)
tree43ed1c0b7cf52a1de313a3576c5b74cd15a7fbe8 /src/mm-port-qmi.c
parent3b79f7379fa71286ac77f7f0be1025129bb9e0dd (diff)
port-qmi: open dpm port automatically in case of IPA net driver
Requires IPA kernel driver to expose the TX and RX endpoint IDs through sysfs. Available from linux 5.14 onwards.
Diffstat (limited to 'src/mm-port-qmi.c')
-rw-r--r--src/mm-port-qmi.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/mm-port-qmi.c b/src/mm-port-qmi.c
index b36bcdff..eb7ccbc6 100644
--- a/src/mm-port-qmi.c
+++ b/src/mm-port-qmi.c
@@ -1130,6 +1130,8 @@ typedef enum {
INTERNAL_SETUP_DATA_FORMAT_STEP_SUPPORTED_KERNEL_DATA_MODES,
INTERNAL_SETUP_DATA_FORMAT_STEP_RETRY,
INTERNAL_SETUP_DATA_FORMAT_STEP_CURRENT_KERNEL_DATA_MODES,
+ INTERNAL_SETUP_DATA_FORMAT_STEP_ALLOCATE_DPM_CLIENT,
+ INTERNAL_SETUP_DATA_FORMAT_STEP_DPM_OPEN,
INTERNAL_SETUP_DATA_FORMAT_STEP_ALLOCATE_WDA_CLIENT,
INTERNAL_SETUP_DATA_FORMAT_STEP_GET_WDA_DATA_FORMAT,
INTERNAL_SETUP_DATA_FORMAT_STEP_QUERY_DONE,
@@ -1156,6 +1158,7 @@ typedef struct {
/* configured device data format */
QmiClient *wda;
+ QmiClient *dpm;
QmiWdaLinkLayerProtocol wda_llp_current;
QmiWdaLinkLayerProtocol wda_llp_requested;
QmiWdaDataAggregationProtocol wda_ul_dap_current;
@@ -1175,7 +1178,15 @@ internal_setup_data_format_context_free (InternalSetupDataFormatContext *ctx)
ctx->wda,
QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID,
3, NULL, NULL, NULL);
+
+ if (ctx->dpm && ctx->device)
+ qmi_device_release_client (ctx->device,
+ ctx->dpm,
+ QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID,
+ 3, NULL, NULL, NULL);
+
g_clear_object (&ctx->wda);
+ g_clear_object (&ctx->dpm);
g_clear_object (&ctx->data);
g_clear_object (&ctx->device);
g_slice_free (InternalSetupDataFormatContext, ctx);
@@ -1599,6 +1610,112 @@ allocate_client_wda_ready (QmiDevice *device,
}
static void
+dpm_open_port_ready (QmiClientDpm *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(QmiMessageDpmOpenPortOutput) output = NULL;
+ InternalSetupDataFormatContext *ctx;
+ g_autoptr(GError) error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ output = qmi_client_dpm_open_port_finish (client, res, &error);
+ if (!output ||
+ !qmi_message_dpm_open_port_output_get_result (output, &error)) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ g_object_unref (task);
+ return;
+ }
+
+ /* Go on to next step */
+ ctx->step++;
+ internal_setup_data_format_context_step (task);
+}
+
+static void
+dpm_open_port (GTask *task)
+{
+ MMPortQmi *self;
+ InternalSetupDataFormatContext *ctx;
+ QmiMessageDpmOpenPortInputHardwareDataPortsElement hw_port;
+ g_autoptr(GArray) hw_data_ports = NULL;
+ g_autoptr(QmiMessageDpmOpenPortInput) input = NULL;
+ g_autofree gchar *tx_sysfs_path = NULL;
+ g_autofree gchar *rx_sysfs_path = NULL;
+ g_autofree gchar *tx_sysfs_str = NULL;
+ g_autofree gchar *rx_sysfs_str = NULL;
+ guint tx_id = 0;
+ guint rx_id = 0;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ tx_sysfs_path = g_build_filename (self->priv->net_sysfs_path, "device", "modem", "tx_endpoint_id", NULL);
+ rx_sysfs_path = g_build_filename (self->priv->net_sysfs_path, "device", "modem", "rx_endpoint_id", NULL);
+
+ if (g_file_get_contents (rx_sysfs_path, &rx_sysfs_str, NULL, NULL) &&
+ g_file_get_contents (tx_sysfs_path, &tx_sysfs_str, NULL, NULL)) {
+ if (rx_sysfs_str && tx_sysfs_str) {
+ mm_get_uint_from_str (rx_sysfs_str, &rx_id);
+ mm_get_uint_from_str (tx_sysfs_str, &tx_id);
+ }
+ }
+
+ if (tx_id == 0 || rx_id == 0) {
+ mm_obj_warn (self, "Unable to read TX and RX endpoint IDs from sysfs. skipping automatic DPM port opening.");
+
+ /* Go on to next step */
+ ctx->step++;
+ internal_setup_data_format_context_step (task);
+ return;
+ }
+
+ mm_obj_dbg (self, "Opening DPM port with TX ID: %u and RX ID: %u", tx_id, rx_id);
+
+ /* The modem TX endpoint connects with the IPA's RX port and the modem RX endpoint connects with the IPA's TX port. */
+ hw_port.rx_endpoint_number = tx_id;
+ hw_port.tx_endpoint_number = rx_id;
+ hw_port.endpoint_type = self->priv->endpoint_type;
+ hw_port.interface_number = self->priv->endpoint_interface_number;
+ hw_data_ports = g_array_new (FALSE, FALSE, sizeof (QmiMessageDpmOpenPortInputHardwareDataPortsElement));
+ g_array_append_val (hw_data_ports, hw_port);
+
+ input = qmi_message_dpm_open_port_input_new ();
+ qmi_message_dpm_open_port_input_set_hardware_data_ports (input,
+ hw_data_ports,
+ NULL);
+ qmi_client_dpm_open_port (QMI_CLIENT_DPM (ctx->dpm),
+ input,
+ 10,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback) dpm_open_port_ready,
+ task);
+}
+
+static void
+allocate_client_dpm_ready (QmiDevice *device,
+ GAsyncResult *res,
+ GTask *task)
+{
+ InternalSetupDataFormatContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ ctx->dpm = qmi_device_allocate_client_finish (device, res, &error);
+ if (!ctx->dpm) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Go on to next step */
+ ctx->step++;
+ internal_setup_data_format_context_step (task);
+}
+
+static void
internal_setup_data_format_context_step (GTask *task)
{
MMPortQmi *self;
@@ -1629,6 +1746,31 @@ internal_setup_data_format_context_step (GTask *task)
ctx->step++;
/* Fall through */
+ case INTERNAL_SETUP_DATA_FORMAT_STEP_ALLOCATE_DPM_CLIENT:
+ /* Only allocate new DPM client on first loop */
+ if ((g_strcmp0 (self->priv->net_driver, "ipa") == 0) && (ctx->data_format_combination_i < 0)) {
+ g_assert (!ctx->dpm);
+ qmi_device_allocate_client (ctx->device,
+ QMI_SERVICE_DPM,
+ QMI_CID_NONE,
+ 10,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback) allocate_client_dpm_ready,
+ task);
+ return;
+ }
+ ctx->step++;
+ /* Fall through */
+
+ case INTERNAL_SETUP_DATA_FORMAT_STEP_DPM_OPEN:
+ /* Only for IPA based setups, open dpm port */
+ if (g_strcmp0 (self->priv->net_driver, "ipa") == 0) {
+ dpm_open_port (task);
+ return;
+ }
+ ctx->step++;
+ /* Fall through */
+
case INTERNAL_SETUP_DATA_FORMAT_STEP_ALLOCATE_WDA_CLIENT:
/* Only allocate new WDA client on first loop */
if (ctx->data_format_combination_i < 0) {