From f5f42bc033e625b528b850a7c6d923aaff63869a Mon Sep 17 00:00:00 2001 From: Gidon Studinski Date: Sun, 17 Mar 2013 09:29:53 +0200 Subject: [PATCH] msm: ipa: Add MBIM tethering support Adds support for MBIM tethering. MBIM is a tethering protocol which is a standard on Windows 8 hosts. IPA has the capabilities to Aggregate / Deaggregate MBIM packets and this patch configures IPA to do so. Change-Id: I60bd068856cc9019777881fd9028105372ece19f Signed-off-by: Gidon Studinski --- arch/arm/mach-msm/include/mach/ipa.h | 8 ++ drivers/platform/msm/ipa/teth_bridge.c | 112 +++++++++++++++++-------- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h index 2010abbc075..cc03c48accb 100644 --- a/arch/arm/mach-msm/include/mach/ipa.h +++ b/arch/arm/mach-msm/include/mach/ipa.h @@ -652,6 +652,8 @@ int teth_bridge_disconnect(void); int teth_bridge_connect(struct teth_bridge_connect_params *connect_params); +int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params); + #else /* CONFIG_IPA */ static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid, @@ -1073,6 +1075,12 @@ static inline int teth_bridge_connect(struct teth_bridge_connect_params return -EPERM; } +static inline int teth_bridge_set_aggr_params(struct teth_aggr_params + *aggr_params) +{ + return -EPERM; +} + #endif /* CONFIG_IPA*/ #endif /* _IPA_H_ */ diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c index 29253cd1143..5b26e413f9c 100644 --- a/drivers/platform/msm/ipa/teth_bridge.c +++ b/drivers/platform/msm/ipa/teth_bridge.c @@ -29,7 +29,6 @@ #define TETH_BRIDGE_DRV_NAME "ipa_tethering_bridge" -#ifdef TETH_DEBUG #define TETH_DBG(fmt, args...) \ pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, \ __func__, __LINE__, ## args) @@ -37,12 +36,6 @@ pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d ENTRY\n", __func__, __LINE__) #define TETH_DBG_FUNC_EXIT() \ pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__) -#else -#define TETH_DBG(fmt, args...) -#define TETH_DBG_FUNC_ENTRY() -#define TETH_DBG_FUNC_EXIT() -#endif - #define TETH_ERR(fmt, args...) \ pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) @@ -62,6 +55,9 @@ #define ETHERTYPE_IPV4 0x0800 #define ETHERTYPE_IPV6 0x86DD +#define TETH_AGGR_MAX_DATAGRAMS_DEFAULT 16 +#define TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT (8*1024) + struct mac_addresses_type { u8 host_pc_mac_addr[ETH_ALEN]; bool host_pc_mac_addr_known; @@ -905,7 +901,6 @@ static void bridge_prod_notify_cb(void *notify_cb_data, int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr) { int res = 0; - struct ipa_rm_create_params bridge_prod_params; TETH_DBG_FUNC_ENTRY(); if (usb_notify_cb_ptr == NULL) { @@ -918,48 +913,34 @@ int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr) *private_data_ptr = NULL; /* Build IPA Resource manager dependency graph */ - bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD; - bridge_prod_params.reg_params.user_data = NULL; - bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb; - res = ipa_rm_create_resource(&bridge_prod_params); - if (res) { - TETH_ERR("ipa_rm_create_resource() failed\n"); - goto bail; - } - res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD, IPA_RM_RESOURCE_USB_CONS); - if (res) { + if (res && res != -EEXIST) { TETH_ERR("ipa_rm_add_dependency() failed\n"); goto bail; } res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD, IPA_RM_RESOURCE_A2_CONS); - if (res) { + if (res && res != -EEXIST) { TETH_ERR("ipa_rm_add_dependency() failed\n"); goto fail_add_dependency_1; } res = ipa_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD, IPA_RM_RESOURCE_A2_CONS); - if (res) { + if (res && res != -EEXIST) { TETH_ERR("ipa_rm_add_dependency() failed\n"); goto fail_add_dependency_2; } res = ipa_rm_add_dependency(IPA_RM_RESOURCE_A2_PROD, IPA_RM_RESOURCE_USB_CONS); - if (res) { + if (res && res != -EEXIST) { TETH_ERR("ipa_rm_add_dependency() failed\n"); goto fail_add_dependency_3; } - init_completion(&teth_ctx->is_bridge_prod_up); - init_completion(&teth_ctx->is_bridge_prod_down); - - /* The default link protocol is Ethernet */ - teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET; goto bail; fail_add_dependency_3: @@ -1001,6 +982,20 @@ int teth_bridge_disconnect(void) if (res == -EINPROGRESS) wait_for_completion(&teth_ctx->is_bridge_prod_down); + /* Initialize statistics */ + memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats)); + + /* Delete IPA Resource manager dependency graph */ + res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD, + IPA_RM_RESOURCE_USB_CONS); + res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD, + IPA_RM_RESOURCE_A2_CONS); + res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD, + IPA_RM_RESOURCE_A2_CONS); + res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD, + IPA_RM_RESOURCE_USB_CONS); + if (res) + TETH_ERR("Failed deleting ipa_rm dependency.\n"); bail: TETH_DBG_FUNC_EXIT(); return res; @@ -1084,9 +1079,11 @@ EXPORT_SYMBOL(teth_bridge_connect); static void set_aggr_default_params(struct teth_aggr_params_link *params) { if (params->max_datagrams == 0) - params->max_datagrams = 16; + params->max_datagrams = + TETH_AGGR_MAX_DATAGRAMS_DEFAULT; if (params->max_transfer_size_byte == 0) - params->max_transfer_size_byte = 16*1024; + params->max_transfer_size_byte = + TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT; } static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol) @@ -1096,11 +1093,38 @@ static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol) memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses)); } +int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params) +{ + int res; + + if (!aggr_params) { + TETH_ERR("Invalid parameter\n"); + return -EINVAL; + } + + memcpy(&teth_ctx->aggr_params, + aggr_params, + sizeof(struct teth_aggr_params)); + set_aggr_default_params(&teth_ctx->aggr_params.dl); + set_aggr_default_params(&teth_ctx->aggr_params.ul); + + teth_ctx->aggr_params_known = true; + res = teth_set_aggregation(); + if (res) { + TETH_ERR("Failed setting aggregation params\n"); + res = -EFAULT; + } + + return res; +} +EXPORT_SYMBOL(teth_bridge_set_aggr_params); + static long teth_bridge_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int res = 0; + struct teth_aggr_params aggr_params; TETH_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd)); @@ -1119,7 +1143,7 @@ static long teth_bridge_ioctl(struct file *filp, case TETH_BRIDGE_IOC_SET_AGGR_PARAMS: TETH_DBG("TETH_BRIDGE_IOC_SET_AGGR_PARAMS ioctl called\n"); - res = copy_from_user(&teth_ctx->aggr_params, + res = copy_from_user(&aggr_params, (struct teth_aggr_params *)arg, sizeof(struct teth_aggr_params)); if (res) { @@ -1127,9 +1151,8 @@ static long teth_bridge_ioctl(struct file *filp, res = -EFAULT; break; } - set_aggr_default_params(&teth_ctx->aggr_params.dl); - set_aggr_default_params(&teth_ctx->aggr_params.ul); - teth_ctx->aggr_params_known = true; + + res = teth_bridge_set_aggr_params(&aggr_params); break; case TETH_BRIDGE_IOC_GET_AGGR_PARAMS: @@ -1201,12 +1224,10 @@ static void set_aggr_capabilities(void) teth_ctx->aggr_caps->num_protocols = NUM_PROTOCOLS; teth_ctx->aggr_caps->prot_caps[0].aggr_prot = TETH_AGGR_PROTOCOL_MBIM; - teth_ctx->aggr_caps->prot_caps[0].max_datagrams = 16; - teth_ctx->aggr_caps->prot_caps[0].max_transfer_size_byte = 16*1024; + set_aggr_default_params(&teth_ctx->aggr_caps->prot_caps[0]); teth_ctx->aggr_caps->prot_caps[1].aggr_prot = TETH_AGGR_PROTOCOL_TLP; - teth_ctx->aggr_caps->prot_caps[1].max_datagrams = 16; - teth_ctx->aggr_caps->prot_caps[1].max_transfer_size_byte = 16*1024; + set_aggr_default_params(&teth_ctx->aggr_caps->prot_caps[1]); } void teth_bridge_get_client_handles(u32 *producer_handle, @@ -1287,7 +1308,7 @@ static ssize_t teth_debugfs_read_aggr_params(struct file *file, aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot, aggr_str, sizeof(aggr_str)-1); - nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN, + nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes, "Aggregation parameters for uplink:\n"); nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes, " Aggregation protocol: %s\n", @@ -1493,6 +1514,7 @@ static const struct file_operations teth_bridge_drv_fops = { int teth_bridge_driver_init(void) { int res; + struct ipa_rm_create_params bridge_prod_params; TETH_DBG("Tethering bridge driver init\n"); teth_ctx = kzalloc(sizeof(*teth_ctx), GFP_KERNEL); @@ -1535,6 +1557,22 @@ int teth_bridge_driver_init(void) teth_ctx->comp_hw_bridge_in_progress = false; teth_debugfs_init(); + + /* Create BRIDGE_PROD entity in IPA Resource Manager */ + bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD; + bridge_prod_params.reg_params.user_data = NULL; + bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb; + res = ipa_rm_create_resource(&bridge_prod_params); + if (res) { + TETH_ERR("ipa_rm_create_resource() failed\n"); + goto fail_cdev_add; + } + init_completion(&teth_ctx->is_bridge_prod_up); + init_completion(&teth_ctx->is_bridge_prod_down); + + /* The default link protocol is Ethernet */ + teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET; + TETH_DBG("Tethering bridge driver init OK\n"); return 0;