From 95f4a232cefe76b4bfc664f8dc37e68471c4a77a Mon Sep 17 00:00:00 2001 From: Joel Selvaraj Date: Wed, 21 Jul 2021 12:55:48 +0530 Subject: 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. --- src/mm-port-qmi.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) (limited to 'src/mm-port-qmi.c') 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); @@ -1598,6 +1609,112 @@ allocate_client_wda_ready (QmiDevice *device, internal_setup_data_format_context_step (task); } +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) { @@ -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) { -- cgit v1.2.3-70-g09d2