Loading drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +195 −77 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ static char dbg_buff[IPA_GSB_MAX_MSG_LEN]; #define IPA_GSB_SKB_HEADROOM 256 #define IPA_GSB_AGGR_BYTE_LIMIT 6 #define IPA_GSB_SKB_DUMMY_HEADER 42 #define IPA_GSB_AGGR_BYTE_LIMIT 14 #define IPA_GSB_AGGR_TIME_LIMIT 1 static struct dentry *dent; Loading Loading @@ -131,7 +132,7 @@ struct ipa_gsb_iface_info { * struct ipa_gsb_context - GSB driver context information * @logbuf: buffer of ipc logging * @logbuf_low: buffer of ipc logging (low priority) * @lock: mutex lock * @lock: global mutex lock for global variables * @prod_hdl: handle for prod pipe * @cons_hdl: handle for cons pipe * @ipa_sys_desc_size: sys pipe desc size Loading @@ -140,6 +141,8 @@ struct ipa_gsb_iface_info { * @num_connected_iface: number of connected interface * @num_resumed_iface: number of resumed interface * @iface: interface information * @iface_lock: interface mutex lock for control path * @iface_spinlock: interface spinlock for data path * @pm_hdl: IPA PM handle */ struct ipa_gsb_context { Loading @@ -154,6 +157,8 @@ struct ipa_gsb_context { int num_connected_iface; int num_resumed_iface; struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE]; struct mutex iface_lock[MAX_SUPPORTED_IFACE]; spinlock_t iface_spinlock[MAX_SUPPORTED_IFACE]; u32 pm_hdl; }; Loading Loading @@ -241,6 +246,7 @@ static void ipa_gsb_debugfs_destroy(void) static int ipa_gsb_driver_init(struct odu_bridge_params *params) { int i; if (!ipa_is_ready()) { IPA_GSB_ERR("IPA is not ready\n"); return -EFAULT; Loading @@ -253,6 +259,10 @@ static int ipa_gsb_driver_init(struct odu_bridge_params *params) return -ENOMEM; mutex_init(&ipa_gsb_ctx->lock); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) { mutex_init(&ipa_gsb_ctx->iface_lock[i]); spin_lock_init(&ipa_gsb_ctx->iface_spinlock[i]); } ipa_gsb_debugfs_init(); return 0; Loading Loading @@ -280,22 +290,36 @@ static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info) "%s_ipv4", iface_info->netdev_name); snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name), "%s_ipv6", iface_info->netdev_name); /* partial header: [hdl][QMAP ID][pkt size][ETH header] */ /* * partial header: * [hdl][QMAP ID][pkt size][Dummy Header][ETH header] */ for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) { hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); /* * Optimization: add dummy header to reserve space * for rndis header, so we can do the skb_clone * instead of deep copy. */ hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II; hdr->hdr[i].is_partial = 1; hdr->hdr[i].is_eth2_ofst_valid = 1; hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr); hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; /* populate iface handle */ hdr->hdr[i].hdr[0] = iface_info->iface_hdl; /* populate src ETH address */ memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6); memcpy(&hdr->hdr[i].hdr[10 + IPA_GSB_SKB_DUMMY_HEADER], iface_info->device_ethaddr, 6); /* populate Ethertype */ if (i == IPA_IP_v4) *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP); *(u16 *)(hdr->hdr[i].hdr + 16 + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IP); else *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6); *(u16 *)(hdr->hdr[i].hdr + 16 + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IPV6); } if (ipa_add_hdr(hdr)) { Loading Loading @@ -412,7 +436,7 @@ static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event) return; } IPA_GSB_DBG("wake up clients\n"); IPA_GSB_DBG_LOW("wake up clients\n"); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) if (ipa_gsb_ctx->iface[i] != NULL) ipa_gsb_ctx->iface[i]->wakeup_request( Loading Loading @@ -462,7 +486,7 @@ int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) if (!params || !params->wakeup_request || !hdl || !params->info.netdev_name || !params->info.tx_dp_notify || !params->info.send_dl_skb) { IPA_GSB_ERR("NULL parameters\n"); IPA_GSB_ERR("Invalid parameters\n"); return -EINVAL; } Loading Loading @@ -583,6 +607,7 @@ static void ipa_gsb_deregister_pm(void) int ipa_bridge_cleanup(u32 hdl) { int i; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; Loading @@ -593,59 +618,49 @@ int ipa_bridge_cleanup(u32 hdl) return -EINVAL; } if (ipa_gsb_ctx->iface[hdl] == NULL) { IPA_GSB_ERR("fail to find interface\n"); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("cannot cleanup when iface is connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]); ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]); spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); kfree(ipa_gsb_ctx->iface[hdl]); ipa_gsb_ctx->iface[hdl] = NULL; ipa_gsb_ctx->iface_hdl[hdl] = false; spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); mutex_lock(&ipa_gsb_ctx->lock); ipa_gsb_ctx->num_iface--; IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); if (ipa_gsb_ctx->num_iface == 0) { ipa_gsb_deregister_pm(); ipa_gsb_debugfs_destroy(); ipc_log_context_destroy(ipa_gsb_ctx->logbuf); ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low); mutex_unlock(&ipa_gsb_ctx->lock); mutex_destroy(&ipa_gsb_ctx->lock); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) mutex_destroy(&ipa_gsb_ctx->iface_lock[i]); kfree(ipa_gsb_ctx); ipa_gsb_ctx = NULL; return 0; } mutex_unlock(&ipa_gsb_ctx->lock); return 0; } EXPORT_SYMBOL(ipa_bridge_cleanup); static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len) { struct sk_buff *skb2 = NULL; skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL); if (likely(skb2)) { skb_reserve(skb2, IPA_GSB_SKB_HEADROOM); memcpy(skb2->data, skb->data, len); skb2->len = len; skb_set_tail_pointer(skb2, len); } return skb2; } static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) { Loading @@ -663,24 +678,56 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, skb = (struct sk_buff *)data; if (skb == NULL) { IPA_GSB_ERR("unexpected NULL data\n"); WARN_ON(1); return; } while (skb->len) { mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data; pkt_size = mux_hdr->pkt_size; /* 4-byte padding */ pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3) - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN); pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3 + IPA_GSB_SKB_DUMMY_HEADER) & ~3) - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER); hdl = mux_hdr->iface_hdl; IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n", if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); break; } IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n", pkt_size, pad_byte, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(*mux_hdr)); skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN); /* remove 4 byte mux header AND dummy header*/ skb_pull(skb, sizeof(*mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER); skb2 = skb_clone(skb, GFP_KERNEL); if (!skb2) { IPA_GSB_ERR("skb_clone failed\n"); WARN_ON(1); break; } skb_trim(skb2, pkt_size + ETH_HLEN); spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); if (ipa_gsb_ctx->iface[hdl] != NULL) { ipa_gsb_ctx->iface[hdl]->send_dl_skb( ipa_gsb_ctx->iface[hdl]->priv, skb2); ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); } else { IPA_GSB_ERR("Invalid hdl: %d, drop the skb\n", hdl); spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); dev_kfree_skb_any(skb2); break; } } if (skb) { dev_kfree_skb_any(skb); skb = NULL; } } Loading @@ -693,6 +740,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, skb = (struct sk_buff *)data; if (skb == NULL) { IPA_GSB_ERR("unexpected NULL data\n"); WARN_ON(1); return; } if (evt != IPA_WRITE_DONE && evt != IPA_RECEIVE) { IPA_GSB_ERR("unexpected event: %d\n", evt); dev_kfree_skb_any(skb); Loading @@ -704,7 +757,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, /* change to host order */ *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); hdl = mux_hdr->iface_hdl; IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("invalid hdl: %d and cb, drop the skb\n", hdl); dev_kfree_skb_any(skb); return; } IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); Loading Loading @@ -742,7 +800,8 @@ static int ipa_gsb_connect_sys_pipe(void) /* configure TX EP */ cons_params.client = IPA_CLIENT_ODU_EMB_CONS; cons_params.ipa_ep_cfg.hdr.hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; Loading Loading @@ -786,13 +845,23 @@ int ipa_bridge_connect(u32 hdl) return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was already connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } Loading @@ -800,13 +869,13 @@ int ipa_bridge_connect(u32 hdl) ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to activate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } ret = ipa_gsb_connect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to connect pipe\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } Loading @@ -822,7 +891,7 @@ int ipa_bridge_connect(u32 hdl) IPA_GSB_DBG("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_connect); Loading Loading @@ -860,13 +929,23 @@ int ipa_bridge_disconnect(u32 hdl) return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was not connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } Loading @@ -874,14 +953,14 @@ int ipa_bridge_disconnect(u32 hdl) ret = ipa_gsb_disconnect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to discon pipes\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to deactivate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } } Loading @@ -899,7 +978,7 @@ int ipa_bridge_disconnect(u32 hdl) ipa_gsb_ctx->num_resumed_iface); } mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_disconnect); Loading @@ -913,25 +992,37 @@ int ipa_bridge_resume(u32 hdl) return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG("iface was already resumed\n"); IPA_GSB_DBG_LOW("iface was already resumed\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->num_resumed_iface == 0) { ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("fail to activate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } Loading @@ -941,17 +1032,17 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_ERR( "fail to start con ep %d\n", ret); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } ipa_gsb_ctx->iface[hdl]->is_resumed = true; ipa_gsb_ctx->num_resumed_iface++; IPA_GSB_DBG("num resumed iface: %d\n", IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_resume); Loading @@ -965,20 +1056,32 @@ int ipa_bridge_suspend(u32 hdl) return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG("iface was already suspended\n"); IPA_GSB_DBG_LOW("iface was already suspended\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->num_resumed_iface == 1) { ret = ipa_stop_gsi_channel( ipa_gsb_ctx->cons_hdl); Loading @@ -986,7 +1089,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_ERR( "fail to stop cons ep %d\n", ret); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } Loading @@ -994,17 +1097,17 @@ int ipa_bridge_suspend(u32 hdl) if (ret) { IPA_GSB_ERR("fail to deactivate ipa pm\n"); ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } ipa_gsb_ctx->iface[hdl]->is_resumed = false; ipa_gsb_ctx->num_resumed_iface--; IPA_GSB_DBG("num resumed iface: %d\n", IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_suspend); Loading @@ -1013,16 +1116,26 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) { int ret; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, bandwidth); if (ret) IPA_GSB_ERR("fail to set perf profile\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } EXPORT_SYMBOL(ipa_bridge_set_perf_profile); Loading @@ -1035,12 +1148,17 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, struct stats iface_stats; int ret; IPA_GSB_DBG("client hdl: %d\n", hdl); IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); iface_stats = ipa_gsb_ctx->iface[hdl]->iface_stats; if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); return -EFAULT; } /* make sure skb has enough headroom */ if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { IPA_GSB_DBG("skb doesn't have enough headroom\n"); IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n"); skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr), 0, GFP_ATOMIC); if (!skb2) { Loading drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +9 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ #define IPA_GENERIC_AGGR_TIME_LIMIT 500 /* 0.5msec */ #define IPA_GENERIC_AGGR_PKT_LIMIT 0 #define IPA_GSB_AGGR_BYTE_LIMIT 14 #define IPA_GSB_RX_BUFF_BASE_SZ 16384 #define IPA_GENERIC_RX_BUFF_BASE_SZ 8192 #define IPA_REAL_GENERIC_RX_BUFF_SZ(X) (SKB_DATA_ALIGN(\ (X) + NET_SKB_PAD) +\ Loading Loading @@ -3049,11 +3052,14 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, /* recycle skb for GSB use case */ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { sys->free_rx_wrapper = ipa3_recycle_rx_wrapper; ipa3_free_rx_wrapper; sys->repl_hdlr = ipa3_replenish_rx_cache_recycle; ipa3_replenish_rx_cache; /* Overwrite buffer size & aggr limit for GSB */ sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ( IPA_GENERIC_RX_BUFF_BASE_SZ); IPA_GSB_RX_BUFF_BASE_SZ); in->ipa_ep_cfg.aggr.aggr_byte_limit = IPA_GSB_AGGR_BYTE_LIMIT; } else { sys->free_rx_wrapper = ipa3_free_rx_wrapper; Loading Loading
drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +195 −77 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ static char dbg_buff[IPA_GSB_MAX_MSG_LEN]; #define IPA_GSB_SKB_HEADROOM 256 #define IPA_GSB_AGGR_BYTE_LIMIT 6 #define IPA_GSB_SKB_DUMMY_HEADER 42 #define IPA_GSB_AGGR_BYTE_LIMIT 14 #define IPA_GSB_AGGR_TIME_LIMIT 1 static struct dentry *dent; Loading Loading @@ -131,7 +132,7 @@ struct ipa_gsb_iface_info { * struct ipa_gsb_context - GSB driver context information * @logbuf: buffer of ipc logging * @logbuf_low: buffer of ipc logging (low priority) * @lock: mutex lock * @lock: global mutex lock for global variables * @prod_hdl: handle for prod pipe * @cons_hdl: handle for cons pipe * @ipa_sys_desc_size: sys pipe desc size Loading @@ -140,6 +141,8 @@ struct ipa_gsb_iface_info { * @num_connected_iface: number of connected interface * @num_resumed_iface: number of resumed interface * @iface: interface information * @iface_lock: interface mutex lock for control path * @iface_spinlock: interface spinlock for data path * @pm_hdl: IPA PM handle */ struct ipa_gsb_context { Loading @@ -154,6 +157,8 @@ struct ipa_gsb_context { int num_connected_iface; int num_resumed_iface; struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE]; struct mutex iface_lock[MAX_SUPPORTED_IFACE]; spinlock_t iface_spinlock[MAX_SUPPORTED_IFACE]; u32 pm_hdl; }; Loading Loading @@ -241,6 +246,7 @@ static void ipa_gsb_debugfs_destroy(void) static int ipa_gsb_driver_init(struct odu_bridge_params *params) { int i; if (!ipa_is_ready()) { IPA_GSB_ERR("IPA is not ready\n"); return -EFAULT; Loading @@ -253,6 +259,10 @@ static int ipa_gsb_driver_init(struct odu_bridge_params *params) return -ENOMEM; mutex_init(&ipa_gsb_ctx->lock); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) { mutex_init(&ipa_gsb_ctx->iface_lock[i]); spin_lock_init(&ipa_gsb_ctx->iface_spinlock[i]); } ipa_gsb_debugfs_init(); return 0; Loading Loading @@ -280,22 +290,36 @@ static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info) "%s_ipv4", iface_info->netdev_name); snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name), "%s_ipv6", iface_info->netdev_name); /* partial header: [hdl][QMAP ID][pkt size][ETH header] */ /* * partial header: * [hdl][QMAP ID][pkt size][Dummy Header][ETH header] */ for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) { hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); /* * Optimization: add dummy header to reserve space * for rndis header, so we can do the skb_clone * instead of deep copy. */ hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II; hdr->hdr[i].is_partial = 1; hdr->hdr[i].is_eth2_ofst_valid = 1; hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr); hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; /* populate iface handle */ hdr->hdr[i].hdr[0] = iface_info->iface_hdl; /* populate src ETH address */ memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6); memcpy(&hdr->hdr[i].hdr[10 + IPA_GSB_SKB_DUMMY_HEADER], iface_info->device_ethaddr, 6); /* populate Ethertype */ if (i == IPA_IP_v4) *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP); *(u16 *)(hdr->hdr[i].hdr + 16 + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IP); else *(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6); *(u16 *)(hdr->hdr[i].hdr + 16 + IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IPV6); } if (ipa_add_hdr(hdr)) { Loading Loading @@ -412,7 +436,7 @@ static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event) return; } IPA_GSB_DBG("wake up clients\n"); IPA_GSB_DBG_LOW("wake up clients\n"); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) if (ipa_gsb_ctx->iface[i] != NULL) ipa_gsb_ctx->iface[i]->wakeup_request( Loading Loading @@ -462,7 +486,7 @@ int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) if (!params || !params->wakeup_request || !hdl || !params->info.netdev_name || !params->info.tx_dp_notify || !params->info.send_dl_skb) { IPA_GSB_ERR("NULL parameters\n"); IPA_GSB_ERR("Invalid parameters\n"); return -EINVAL; } Loading Loading @@ -583,6 +607,7 @@ static void ipa_gsb_deregister_pm(void) int ipa_bridge_cleanup(u32 hdl) { int i; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; Loading @@ -593,59 +618,49 @@ int ipa_bridge_cleanup(u32 hdl) return -EINVAL; } if (ipa_gsb_ctx->iface[hdl] == NULL) { IPA_GSB_ERR("fail to find interface\n"); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("cannot cleanup when iface is connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]); ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]); spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); kfree(ipa_gsb_ctx->iface[hdl]); ipa_gsb_ctx->iface[hdl] = NULL; ipa_gsb_ctx->iface_hdl[hdl] = false; spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); mutex_lock(&ipa_gsb_ctx->lock); ipa_gsb_ctx->num_iface--; IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); if (ipa_gsb_ctx->num_iface == 0) { ipa_gsb_deregister_pm(); ipa_gsb_debugfs_destroy(); ipc_log_context_destroy(ipa_gsb_ctx->logbuf); ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low); mutex_unlock(&ipa_gsb_ctx->lock); mutex_destroy(&ipa_gsb_ctx->lock); for (i = 0; i < MAX_SUPPORTED_IFACE; i++) mutex_destroy(&ipa_gsb_ctx->iface_lock[i]); kfree(ipa_gsb_ctx); ipa_gsb_ctx = NULL; return 0; } mutex_unlock(&ipa_gsb_ctx->lock); return 0; } EXPORT_SYMBOL(ipa_bridge_cleanup); static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len) { struct sk_buff *skb2 = NULL; skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL); if (likely(skb2)) { skb_reserve(skb2, IPA_GSB_SKB_HEADROOM); memcpy(skb2->data, skb->data, len); skb2->len = len; skb_set_tail_pointer(skb2, len); } return skb2; } static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) { Loading @@ -663,24 +678,56 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, skb = (struct sk_buff *)data; if (skb == NULL) { IPA_GSB_ERR("unexpected NULL data\n"); WARN_ON(1); return; } while (skb->len) { mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data; pkt_size = mux_hdr->pkt_size; /* 4-byte padding */ pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3) - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN); pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3 + IPA_GSB_SKB_DUMMY_HEADER) & ~3) - (pkt_size + sizeof(*mux_hdr) + ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER); hdl = mux_hdr->iface_hdl; IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n", if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); break; } IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n", pkt_size, pad_byte, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(*mux_hdr)); skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN); /* remove 4 byte mux header AND dummy header*/ skb_pull(skb, sizeof(*mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER); skb2 = skb_clone(skb, GFP_KERNEL); if (!skb2) { IPA_GSB_ERR("skb_clone failed\n"); WARN_ON(1); break; } skb_trim(skb2, pkt_size + ETH_HLEN); spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); if (ipa_gsb_ctx->iface[hdl] != NULL) { ipa_gsb_ctx->iface[hdl]->send_dl_skb( ipa_gsb_ctx->iface[hdl]->priv, skb2); ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); } else { IPA_GSB_ERR("Invalid hdl: %d, drop the skb\n", hdl); spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); dev_kfree_skb_any(skb2); break; } } if (skb) { dev_kfree_skb_any(skb); skb = NULL; } } Loading @@ -693,6 +740,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, skb = (struct sk_buff *)data; if (skb == NULL) { IPA_GSB_ERR("unexpected NULL data\n"); WARN_ON(1); return; } if (evt != IPA_WRITE_DONE && evt != IPA_RECEIVE) { IPA_GSB_ERR("unexpected event: %d\n", evt); dev_kfree_skb_any(skb); Loading @@ -704,7 +757,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, /* change to host order */ *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); hdl = mux_hdr->iface_hdl; IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("invalid hdl: %d and cb, drop the skb\n", hdl); dev_kfree_skb_any(skb); return; } IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); Loading Loading @@ -742,7 +800,8 @@ static int ipa_gsb_connect_sys_pipe(void) /* configure TX EP */ cons_params.client = IPA_CLIENT_ODU_EMB_CONS; cons_params.ipa_ep_cfg.hdr.hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr); ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; Loading Loading @@ -786,13 +845,23 @@ int ipa_bridge_connect(u32 hdl) return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was already connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } Loading @@ -800,13 +869,13 @@ int ipa_bridge_connect(u32 hdl) ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to activate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } ret = ipa_gsb_connect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to connect pipe\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } Loading @@ -822,7 +891,7 @@ int ipa_bridge_connect(u32 hdl) IPA_GSB_DBG("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_connect); Loading Loading @@ -860,13 +929,23 @@ int ipa_bridge_disconnect(u32 hdl) return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was not connected\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } Loading @@ -874,14 +953,14 @@ int ipa_bridge_disconnect(u32 hdl) ret = ipa_gsb_disconnect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to discon pipes\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to deactivate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } } Loading @@ -899,7 +978,7 @@ int ipa_bridge_disconnect(u32 hdl) ipa_gsb_ctx->num_resumed_iface); } mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_disconnect); Loading @@ -913,25 +992,37 @@ int ipa_bridge_resume(u32 hdl) return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG("iface was already resumed\n"); IPA_GSB_DBG_LOW("iface was already resumed\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->num_resumed_iface == 0) { ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("fail to activate ipa pm\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } Loading @@ -941,17 +1032,17 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_ERR( "fail to start con ep %d\n", ret); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } ipa_gsb_ctx->iface[hdl]->is_resumed = true; ipa_gsb_ctx->num_resumed_iface++; IPA_GSB_DBG("num resumed iface: %d\n", IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_resume); Loading @@ -965,20 +1056,32 @@ int ipa_bridge_suspend(u32 hdl) return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG("iface was already suspended\n"); IPA_GSB_DBG_LOW("iface was already suspended\n"); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->num_resumed_iface == 1) { ret = ipa_stop_gsi_channel( ipa_gsb_ctx->cons_hdl); Loading @@ -986,7 +1089,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_ERR( "fail to stop cons ep %d\n", ret); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } Loading @@ -994,17 +1097,17 @@ int ipa_bridge_suspend(u32 hdl) if (ret) { IPA_GSB_ERR("fail to deactivate ipa pm\n"); ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } ipa_gsb_ctx->iface[hdl]->is_resumed = false; ipa_gsb_ctx->num_resumed_iface--; IPA_GSB_DBG("num resumed iface: %d\n", IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_suspend); Loading @@ -1013,16 +1116,26 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) { int ret; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; } if (hdl >= MAX_SUPPORTED_IFACE) { IPA_GSB_ERR("invalid hdl: %d\n", hdl); return -EINVAL; } IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth); mutex_lock(&ipa_gsb_ctx->lock); mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, bandwidth); if (ret) IPA_GSB_ERR("fail to set perf profile\n"); mutex_unlock(&ipa_gsb_ctx->lock); mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } EXPORT_SYMBOL(ipa_bridge_set_perf_profile); Loading @@ -1035,12 +1148,17 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, struct stats iface_stats; int ret; IPA_GSB_DBG("client hdl: %d\n", hdl); IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); iface_stats = ipa_gsb_ctx->iface[hdl]->iface_stats; if (!ipa_gsb_ctx->iface[hdl]) { IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); return -EFAULT; } /* make sure skb has enough headroom */ if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { IPA_GSB_DBG("skb doesn't have enough headroom\n"); IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n"); skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr), 0, GFP_ATOMIC); if (!skb2) { Loading
drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +9 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ #define IPA_GENERIC_AGGR_TIME_LIMIT 500 /* 0.5msec */ #define IPA_GENERIC_AGGR_PKT_LIMIT 0 #define IPA_GSB_AGGR_BYTE_LIMIT 14 #define IPA_GSB_RX_BUFF_BASE_SZ 16384 #define IPA_GENERIC_RX_BUFF_BASE_SZ 8192 #define IPA_REAL_GENERIC_RX_BUFF_SZ(X) (SKB_DATA_ALIGN(\ (X) + NET_SKB_PAD) +\ Loading Loading @@ -3049,11 +3052,14 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, /* recycle skb for GSB use case */ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) { sys->free_rx_wrapper = ipa3_recycle_rx_wrapper; ipa3_free_rx_wrapper; sys->repl_hdlr = ipa3_replenish_rx_cache_recycle; ipa3_replenish_rx_cache; /* Overwrite buffer size & aggr limit for GSB */ sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ( IPA_GENERIC_RX_BUFF_BASE_SZ); IPA_GSB_RX_BUFF_BASE_SZ); in->ipa_ep_cfg.aggr.aggr_byte_limit = IPA_GSB_AGGR_BYTE_LIMIT; } else { sys->free_rx_wrapper = ipa3_free_rx_wrapper; Loading