From cd6fd44586aec75341baf3c6548aadfa00c33dbe Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 1 Jul 2019 03:43:21 +0530 Subject: [PATCH] ipa: Add support in ipa-usb driver for rmnet_cv2x Only one RmNET instance is supported till now, so there was a check to not to support additional protocol in ipa usb driver. With respect to auto use case requirement we need to support two rmnet instance, newly added rmnet_cv2x along with legacy rmnet. Modify code to support additional rmnet_cv2x teth interface with respect to protocol, pm states. Change-Id: I83984de859919a395f1115c8e2a37004d01f0688 Signed-off-by: Mohammed Javid --- .../platform/msm/ipa/ipa_clients/ipa_usb.c | 159 +++++++++++++++--- drivers/platform/msm/ipa/ipa_v3/ipa.c | 7 + drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 + drivers/platform/msm/ipa/ipa_v3/teth_bridge.c | 75 +++++++-- include/linux/ipa.h | 1 + include/linux/ipa_usb.h | 9 +- 7 files changed, 208 insertions(+), 47 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index e626b97727db..fa7fa640f3ef 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -144,13 +144,15 @@ enum ipa3_usb_state { enum ipa3_usb_transport_type { IPA_USB_TRANSPORT_TETH, IPA_USB_TRANSPORT_DPL, + IPA_USB_TRANSPORT_TETH_2, IPA_USB_TRANSPORT_MAX }; /* Get transport type from tethering protocol */ #define IPA3_USB_GET_TTYPE(__teth_prot) \ (((__teth_prot) == IPA_USB_DIAG) ? \ - IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH) + IPA_USB_TRANSPORT_DPL : (((__teth_prot) == IPA_USB_RMNET_CV2X) ? \ + IPA_USB_TRANSPORT_TETH_2 : IPA_USB_TRANSPORT_TETH)) /* Does the given transport type is DPL? */ #define IPA3_USB_IS_TTYPE_DPL(__ttype) \ @@ -204,7 +206,7 @@ struct ipa3_usb_context { struct ipa3_usb_teth_prot_context teth_prot_ctx[IPA_USB_MAX_TETH_PROT_SIZE]; int num_init_prot; /* without dpl */ - struct teth_bridge_init_params teth_bridge_params; + struct teth_bridge_init_params teth_bridge_params[IPA_TETH_BRIDGE_MAX]; struct completion dev_ready_comp; u32 qmi_req_id; spinlock_t state_lock; @@ -770,6 +772,8 @@ static char *ipa3_usb_teth_prot_to_string(enum ipa_usb_teth_prot teth_prot) case IPA_USB_RMNET: case IPA_USB_MBIM: return "teth_bridge"; + case IPA_USB_RMNET_CV2X: + return "teth_bridge_cv2x"; case IPA_USB_DIAG: return "dpl"; default: @@ -785,6 +789,8 @@ static char *ipa3_usb_teth_bridge_prot_to_string( switch (teth_prot) { case IPA_USB_RMNET: return "rmnet"; + case IPA_USB_RMNET_CV2X: + return "rmnet_cv2x"; case IPA_USB_MBIM: return "mbim"; default: @@ -794,11 +800,18 @@ static char *ipa3_usb_teth_bridge_prot_to_string( return "unsupported"; } -static int ipa3_usb_init_teth_bridge(void) +static int ipa3_usb_init_teth_bridge(enum ipa_usb_teth_prot teth_prot) { int result; - result = teth_bridge_init(&ipa3_usb_ctx->teth_bridge_params); + if (teth_prot == IPA_USB_RMNET_CV2X) + result = + teth_bridge_init( + &ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2]); + else + result = + teth_bridge_init( + &ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1]); if (result) { IPA_USB_ERR("Failed to initialize teth_bridge\n"); return result; @@ -812,15 +825,26 @@ static int ipa3_usb_register_pm(enum ipa3_usb_transport_type ttype) struct ipa3_usb_transport_type_ctx *ttype_ctx = &ipa3_usb_ctx->ttype_ctx[ttype]; int result; + enum ipa_client_type consumer; - /* there is one PM resource for teth and one for DPL */ - if (!IPA3_USB_IS_TTYPE_DPL(ttype) && ipa3_usb_ctx->num_init_prot > 0) + /* + * One PM resource for teth1, + * One PM resource for teth2 (CV2X), + * One for DPL, + */ + + if (!IPA3_USB_IS_TTYPE_DPL(ttype) && (ipa3_usb_ctx->num_init_prot > 0) + && (ttype != IPA_USB_TRANSPORT_TETH_2)) return 0; memset(&ttype_ctx->pm_ctx.reg_params, 0, sizeof(ttype_ctx->pm_ctx.reg_params)); - ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ? - "USB DPL" : "USB"; + ttype_ctx->pm_ctx.reg_params.name = + (ttype == IPA_USB_TRANSPORT_DPL) ? + "USB DPL" : + (ttype == IPA_USB_TRANSPORT_TETH_2) ? + "USB2" : "USB"; + ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb; ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx; ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT; @@ -832,9 +856,12 @@ static int ipa3_usb_register_pm(enum ipa3_usb_transport_type ttype) goto fail_pm_reg; } + consumer = (ttype == IPA_USB_TRANSPORT_DPL) ? + IPA_CLIENT_USB_DPL_CONS : + (ttype == IPA_USB_TRANSPORT_TETH_2) ? + IPA_CLIENT_USB2_CONS : IPA_CLIENT_USB_CONS; result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl, - (ttype == IPA_USB_TRANSPORT_DPL) ? - IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS); + consumer); if (result) { IPA_USB_ERR("fail to associate cons with PM %d\n", result); goto fail_pm_cons; @@ -1121,9 +1148,11 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, goto bad_params; } ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data; - result = ipa3_usb_init_teth_bridge(); + + result = ipa3_usb_init_teth_bridge(teth_prot); if (result) goto teth_prot_init_fail; + ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = IPA_USB_TETH_PROT_INITIALIZED; ipa3_usb_ctx->num_init_prot++; @@ -1139,6 +1168,26 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, ipa3_register_client_callback(&ipa_usb_set_lock_unlock, &ipa3_usb_get_teth_port_state, IPA_CLIENT_USB_PROD); break; + case IPA_USB_RMNET_CV2X: + if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state != + IPA_USB_TETH_PROT_INVALID) { + IPA_USB_DBG("%s already initialized\n", + ipa3_usb_teth_prot_to_string(teth_prot)); + result = -EPERM; + goto bad_params; + } + ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = user_data; + + result = ipa3_usb_init_teth_bridge(teth_prot); + if (result) + goto teth_prot_init_fail; + + ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = + IPA_USB_TETH_PROT_INITIALIZED; + IPA_USB_DBG("initialized %s %s\n", + ipa3_usb_teth_prot_to_string(teth_prot), + ipa3_usb_teth_bridge_prot_to_string(teth_prot)); + break; case IPA_USB_DIAG: if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state != IPA_USB_TETH_PROT_INVALID) { @@ -1166,7 +1215,8 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, teth_prot_init_fail: if ((IPA3_USB_IS_TTYPE_DPL(ttype)) - || (ipa3_usb_ctx->num_init_prot == 0)) { + || (ipa3_usb_ctx->num_init_prot == 0) + || (teth_prot == IPA_USB_RMNET_CV2X)) { if (ipa_pm_is_used()) { ipa3_usb_deregister_pm(ttype); } else { @@ -1249,6 +1299,7 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) } break; case IPA_USB_RMNET: + case IPA_USB_RMNET_CV2X: case IPA_USB_MBIM: if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state == IPA_USB_TETH_PROT_INVALID) { @@ -1319,7 +1370,6 @@ static int ipa3_usb_smmu_map_xdci_channel( ipa3_usb_ctx->smmu_reg_map.cnt--; } - result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova, params->xfer_ring_len, map, params->sgt_xfer_rings, IPA_SMMU_CB_AP); @@ -1396,11 +1446,19 @@ static int ipa3_usb_request_xdci_channel( case IPA_USB_RMNET: case IPA_USB_MBIM: chan_params.priv = - ipa3_usb_ctx->teth_bridge_params.private_data; + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].private_data; chan_params.notify = - ipa3_usb_ctx->teth_bridge_params.usb_notify_cb; + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].usb_notify_cb; chan_params.skip_ep_cfg = - ipa3_usb_ctx->teth_bridge_params.skip_ep_cfg; + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_1].skip_ep_cfg; + break; + case IPA_USB_RMNET_CV2X: + chan_params.priv = + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].private_data; + chan_params.notify = + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].usb_notify_cb; + chan_params.skip_ep_cfg = + ipa3_usb_ctx->teth_bridge_params[IPA_TETH_BRIDGE_2].skip_ep_cfg; break; case IPA_USB_DIAG: chan_params.priv = NULL; @@ -1703,6 +1761,16 @@ static int ipa3_usb_connect_dpl(void) return 0; } +static int ipa3_get_tethering_mode(enum ipa_usb_teth_prot teth_prot) +{ + if (teth_prot == IPA_USB_RMNET) + return TETH_TETHERING_MODE_RMNET; + else if (teth_prot == IPA_USB_RMNET_CV2X) + return TETH_TETHERING_MODE_RMNET_2; + else + return TETH_TETHERING_MODE_MBIM; +} + static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) { int result; @@ -1771,6 +1839,7 @@ static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_RMNET: + case IPA_USB_RMNET_CV2X: case IPA_USB_MBIM: if (teth_prot_ptr->state == IPA_USB_TETH_PROT_CONNECTED) { @@ -1778,7 +1847,8 @@ static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) ipa3_usb_teth_prot_to_string(teth_prot)); break; } - result = ipa3_usb_init_teth_bridge(); + + result = ipa3_usb_init_teth_bridge(teth_prot); if (result) return result; @@ -1789,14 +1859,19 @@ static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) teth_bridge_params.usb_ipa_pipe_hdl = teth_conn_params->usb_to_ipa_clnt_hdl; teth_bridge_params.tethering_mode = - (teth_prot == IPA_USB_RMNET) ? - (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM); - teth_bridge_params.client_type = IPA_CLIENT_USB_PROD; + ipa3_get_tethering_mode(teth_prot); + + if (teth_prot == IPA_USB_RMNET_CV2X) + teth_bridge_params.client_type = IPA_CLIENT_USB2_PROD; + else + teth_bridge_params.client_type = IPA_CLIENT_USB_PROD; + result = ipa3_usb_connect_teth_bridge(&teth_bridge_params); if (result) { ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } + ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); @@ -1835,11 +1910,15 @@ static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) return 0; } -static int ipa3_usb_disconnect_teth_bridge(void) +static int ipa3_usb_disconnect_teth_bridge(enum ipa_usb_teth_prot teth_prot) { int result; - result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD); + if (teth_prot == IPA_USB_RMNET_CV2X) + result = teth_bridge_disconnect(IPA_CLIENT_USB2_PROD); + else + result = teth_bridge_disconnect(IPA_CLIENT_USB_PROD); + if (result) { IPA_USB_ERR("failed to disconnect teth_bridge\n"); return result; @@ -1904,6 +1983,7 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot) ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_RMNET: + case IPA_USB_RMNET_CV2X: case IPA_USB_MBIM: if (teth_prot_ptr->state != IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s (%s) is not connected\n", @@ -1911,7 +1991,8 @@ static int ipa3_usb_disconnect_teth_prot(enum ipa_usb_teth_prot teth_prot) ipa3_usb_teth_bridge_prot_to_string(teth_prot)); return -EPERM; } - result = ipa3_usb_disconnect_teth_bridge(); + + result = ipa3_usb_disconnect_teth_bridge(teth_prot); if (result) break; @@ -1957,8 +2038,7 @@ static int ipa3_usb_xdci_connect_internal( return -EINVAL; } - ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL : - IPA_USB_TRANSPORT_TETH; + ttype = IPA3_USB_GET_TTYPE(params->teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) { IPA_USB_ERR("Illegal operation\n"); @@ -2159,7 +2239,9 @@ static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status) for (i = 0 ; i < IPA_USB_MAX_TETH_PROT_SIZE ; i++) { if (ipa3_usb_ctx->teth_prot_ctx[i].state == IPA_USB_TETH_PROT_INITIALIZED) { - if ((i == IPA_USB_RMNET) || (i == IPA_USB_MBIM)) + if ((i == IPA_USB_RMNET) || + (i == IPA_USB_MBIM) || + (i == IPA_USB_RMNET_CV2X)) status->inited_prots[status->num_init_prot++] = ipa3_usb_teth_bridge_prot_to_string(i); else @@ -2169,6 +2251,7 @@ static int ipa3_usb_get_status_dbg_info(struct ipa3_usb_status_dbg_info *status) IPA_USB_TETH_PROT_CONNECTED) { switch (i) { case IPA_USB_RMNET: + case IPA_USB_RMNET_CV2X: case IPA_USB_MBIM: status->teth_connected_prot = ipa3_usb_teth_bridge_prot_to_string(i); @@ -2652,6 +2735,24 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) ipa3_usb_teth_prot_to_string(teth_prot), ipa3_usb_teth_bridge_prot_to_string(teth_prot)); break; + case IPA_USB_RMNET_CV2X: + if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state != + IPA_USB_TETH_PROT_INITIALIZED) { + IPA_USB_ERR("%s (%s) is not initialized\n", + ipa3_usb_teth_prot_to_string(teth_prot), + ipa3_usb_teth_bridge_prot_to_string(teth_prot)); + result = -EINVAL; + goto bad_params; + } + + ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data = + NULL; + ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = + IPA_USB_TETH_PROT_INVALID; + IPA_USB_DBG("deinitialized %s (%s)\n", + ipa3_usb_teth_prot_to_string(teth_prot), + ipa3_usb_teth_bridge_prot_to_string(teth_prot)); + break; case IPA_USB_DIAG: if (teth_prot_ptr->state != IPA_USB_TETH_PROT_INITIALIZED) { @@ -2672,7 +2773,8 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) } if (IPA3_USB_IS_TTYPE_DPL(ttype) || - (ipa3_usb_ctx->num_init_prot == 0)) { + (ipa3_usb_ctx->num_init_prot == 0) || + (teth_prot == IPA_USB_RMNET_CV2X)) { if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype)) IPA_USB_ERR( "failed to change state to invalid\n"); @@ -3121,6 +3223,9 @@ static int __init ipa3_usb_init(void) pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx; pm_ctx->hdl = ~0; pm_ctx->remote_wakeup_work = &ipa3_usb_notify_remote_wakeup_work; + pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH_2].pm_ctx; + pm_ctx->hdl = ~0; + pm_ctx->remote_wakeup_work = &ipa3_usb_notify_remote_wakeup_work; pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx; pm_ctx->hdl = ~0; pm_ctx->remote_wakeup_work = &ipa3_usb_dpl_notify_remote_wakeup_work; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 4c17c7ebec09..3274f6b1f32c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -3584,13 +3584,20 @@ void ipa3_q6_pre_shutdown_cleanup(void) /* Remove delay from Q6 PRODs to avoid pending descriptors * on pipe reset procedure */ + if (!ipa3_ctx->ipa_endp_delay_wa) { ipa3_q6_pipe_delay(false); ipa3_set_reset_client_prod_pipe_delay(true, IPA_CLIENT_USB_PROD); + if (ipa3_ctx->ipa_config_is_auto) + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_USB2_PROD); } else { ipa3_start_stop_client_prod_gsi_chnl(IPA_CLIENT_USB_PROD, false); + if (ipa3_ctx->ipa_config_is_auto) + ipa3_start_stop_client_prod_gsi_chnl( + IPA_CLIENT_USB2_PROD, false); } IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index b43d7adda1e9..d5343bcd6424 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2586,7 +2586,7 @@ int ipa3_teth_bridge_disconnect(enum ipa_client_type client); int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params); -int ipa3_teth_bridge_get_pm_hdl(void); +int ipa3_teth_bridge_get_pm_hdl(enum ipa_client_type client); /* * Tethering client info diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 4dea4390f4d8..fd13d195ff7c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3002,6 +3002,7 @@ bool ipa3_should_pipe_be_suspended(enum ipa_client_type client) return false; if (client == IPA_CLIENT_USB_CONS || + client == IPA_CLIENT_USB2_CONS || client == IPA_CLIENT_USB_DPL_CONS || client == IPA_CLIENT_MHI_CONS || client == IPA_CLIENT_MHI_DPL_CONS || @@ -5081,6 +5082,7 @@ int ipa3_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) meta.qmap_id = param_in->qmap_id; if (param_in->client == IPA_CLIENT_USB_PROD || + param_in->client == IPA_CLIENT_USB2_PROD || param_in->client == IPA_CLIENT_HSIC1_PROD || param_in->client == IPA_CLIENT_ODU_PROD || param_in->client == IPA_CLIENT_ETHERNET_PROD || diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c index bbb3f3d0c7a0..4175e25dbd77 100644 --- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c +++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c @@ -38,6 +38,12 @@ #define TETH_ERR(fmt, args...) \ pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) +enum ipa_num_teth_iface { + IPA_TETH_IFACE_1 = 0, + IPA_TETH_IFACE_2 = 1, + IPA_TETH_IFACE_MAX +}; + /** * struct ipa3_teth_bridge_ctx - Tethering bridge driver context information * @class: kernel class pointer @@ -50,7 +56,7 @@ struct ipa3_teth_bridge_ctx { dev_t dev_num; struct device *dev; struct cdev cdev; - u32 modem_pm_hdl; + u32 modem_pm_hdl[IPA_TETH_IFACE_MAX]; }; static struct ipa3_teth_bridge_ctx *ipa3_teth_ctx; @@ -121,19 +127,25 @@ int ipa3_teth_bridge_init(struct teth_bridge_init_params *params) * Return codes: handle * -EINVAL - Bad parameter */ -int ipa3_teth_bridge_get_pm_hdl(void) +int ipa3_teth_bridge_get_pm_hdl(enum ipa_client_type client) { - TETH_DBG_FUNC_ENTRY(); + u32 pm_hdl; - if (ipa3_teth_ctx->modem_pm_hdl == ~0) { + TETH_DBG_FUNC_ENTRY(); + if (client == IPA_CLIENT_USB2_PROD) + pm_hdl = ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_2]; + else + pm_hdl = ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_1]; + + if (pm_hdl == ~0) { TETH_ERR("Bad parameter\n"); TETH_DBG_FUNC_EXIT(); return -EINVAL; } - TETH_DBG("Return rm-handle %d\n", ipa3_teth_ctx->modem_pm_hdl); + TETH_DBG("Return pm-handle %d\n", pm_hdl); TETH_DBG_FUNC_EXIT(); - return ipa3_teth_ctx->modem_pm_hdl; + return pm_hdl; } /** @@ -142,21 +154,32 @@ int ipa3_teth_bridge_get_pm_hdl(void) int ipa3_teth_bridge_disconnect(enum ipa_client_type client) { int res = 0; + int *pm_hdl = NULL; TETH_DBG_FUNC_ENTRY(); if (ipa_pm_is_used()) { - res = ipa_pm_deactivate_sync(ipa3_teth_ctx->modem_pm_hdl); + + if (client == IPA_CLIENT_USB2_PROD) + pm_hdl = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_2]; + else + pm_hdl = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_1]; + + res = ipa_pm_deactivate_sync(*pm_hdl); if (res) { TETH_ERR("fail to deactivate modem %d\n", res); return res; } - res = ipa_pm_deregister(ipa3_teth_ctx->modem_pm_hdl); - ipa3_teth_ctx->modem_pm_hdl = ~0; + res = ipa_pm_deregister(*pm_hdl); + *pm_hdl = ~0; } else { - ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD, - IPA_RM_RESOURCE_Q6_CONS); - ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, - IPA_RM_RESOURCE_USB_CONS); + if (client == IPA_CLIENT_USB2_PROD) { + TETH_ERR("No support for rm added/validated.\n"); + } else { + ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD, + IPA_RM_RESOURCE_Q6_CONS); + ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD, + IPA_RM_RESOURCE_USB_CONS); + } } TETH_DBG_FUNC_EXIT(); @@ -176,22 +199,36 @@ int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params) { int res = 0; struct ipa_pm_register_params reg_params; + u32 *pm = NULL; memset(®_params, 0, sizeof(reg_params)); TETH_DBG_FUNC_ENTRY(); if (ipa_pm_is_used()) { - reg_params.name = "MODEM (USB RMNET)"; + if (connect_params->tethering_mode == + TETH_TETHERING_MODE_RMNET_2) { + reg_params.name = "MODEM (USB RMNET_CV2X)"; + pm = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_2]; + } else { + reg_params.name = "MODEM (USB RMNET)"; + pm = &ipa3_teth_ctx->modem_pm_hdl[IPA_TETH_IFACE_1]; + } reg_params.group = IPA_PM_GROUP_MODEM; reg_params.skip_clk_vote = true; res = ipa_pm_register(®_params, - &ipa3_teth_ctx->modem_pm_hdl); + pm); if (res) { TETH_ERR("fail to register with PM %d\n", res); return res; } - res = ipa_pm_activate_sync(ipa3_teth_ctx->modem_pm_hdl); + res = ipa_pm_activate_sync(*pm); + goto bail; + } + + if (connect_params->tethering_mode == TETH_TETHERING_MODE_RMNET_2) { + res = -EINVAL; + TETH_ERR("No support for rm added/validated.\n"); goto bail; } @@ -246,7 +283,7 @@ static const struct file_operations ipa3_teth_bridge_drv_fops = { */ int ipa3_teth_bridge_driver_init(void) { - int res; + int res, i; TETH_DBG("Tethering bridge driver init\n"); ipa3_teth_ctx = kzalloc(sizeof(*ipa3_teth_ctx), GFP_KERNEL); @@ -285,7 +322,9 @@ int ipa3_teth_bridge_driver_init(void) goto fail_cdev_add; } - ipa3_teth_ctx->modem_pm_hdl = ~0; + for (i = 0; i < IPA_TETH_IFACE_MAX; i++) + ipa3_teth_ctx->modem_pm_hdl[i] = ~0; + TETH_DBG("Tethering bridge driver init OK\n"); return 0; diff --git a/include/linux/ipa.h b/include/linux/ipa.h index 19113b259daf..a99cad2912c7 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -747,6 +747,7 @@ struct ipa_rm_perf_profile { enum teth_tethering_mode { TETH_TETHERING_MODE_RMNET, TETH_TETHERING_MODE_MBIM, + TETH_TETHERING_MODE_RMNET_2, TETH_TETHERING_MODE_MAX, }; diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h index 98ec5babf299..7e78ec0aa987 100644 --- a/include/linux/ipa_usb.h +++ b/include/linux/ipa_usb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,9 +19,16 @@ enum ipa_usb_teth_prot { IPA_USB_RMNET = 2, IPA_USB_MBIM = 3, IPA_USB_DIAG = 4, + IPA_USB_RMNET_CV2X = 5, IPA_USB_MAX_TETH_PROT_SIZE }; +enum teth_bridge_params { + IPA_TETH_BRIDGE_1 = 0, + IPA_TETH_BRIDGE_2 = 1, + IPA_TETH_BRIDGE_MAX +}; + /** * ipa_usb_teth_params - parameters for RDNIS/ECM initialization API *