Loading arch/arm/mach-msm/include/mach/ipa.h +13 −2 Original line number Diff line number Diff line Loading @@ -678,6 +678,17 @@ struct ipa_tx_data_desc { u16 pyld_len; }; /** * struct ipa_rx_data - information needed * to send to wlan driver on receiving data from ipa hw * @skb: skb * @dma_addr: DMA address of this Rx packet */ struct ipa_rx_data { struct sk_buff *skb; dma_addr_t dma_addr; }; #ifdef CONFIG_IPA /* Loading Loading @@ -833,7 +844,7 @@ int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, int ipa_tx_dp_mul(enum ipa_client_type dst, struct ipa_tx_data_desc *data_desc); void ipa_free_skb(struct sk_buff *); void ipa_free_skb(struct ipa_rx_data *); /* * System pipes Loading Loading @@ -1285,7 +1296,7 @@ static inline int ipa_tx_dp_mul( return -EPERM; } static inline void ipa_free_skb(struct sk_buff *skb) static inline void ipa_free_skb(struct ipa_rx_data *rx_in) { return; } Loading drivers/platform/msm/ipa/ipa.c +6 −0 Original line number Diff line number Diff line Loading @@ -1976,6 +1976,12 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, mutex_init(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->ipa_active_clients = 0; /* wlan related member */ spin_lock_init(&ipa_ctx->wlan_spinlock); spin_lock_init(&ipa_ctx->ipa_tx_mul_spinlock); ipa_ctx->wlan_comm_cnt = 0; INIT_LIST_HEAD(&ipa_ctx->wlan_comm_desc_list); memset(&ipa_ctx->wstats, 0, sizeof(struct ipa_wlan_stats)); /* enable IPA clocks until the end of the initialization */ ipa_inc_client_enable_clks(); Loading drivers/platform/msm/ipa/ipa_debugfs.c +75 −14 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ static struct dentry *dfile_ip6_rt; static struct dentry *dfile_ip4_flt; static struct dentry *dfile_ip6_flt; static struct dentry *dfile_stats; static struct dentry *dfile_wstats; static struct dentry *dfile_dbg_cnt; static struct dentry *dfile_msg; static struct dentry *dfile_ip4_nat; Loading Loading @@ -748,10 +749,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, "a2_power_off_reqs_in=%u\n" "a2_power_off_reqs_out=%u\n" "a2_power_modem_acks=%u\n" "a2_power_apps_acks=%u\n" "wlan_rx_pkts=%u\n" "wlan_rx_comp=%u\n" "wlan_tx_pkts=%u\n", "a2_power_apps_acks=%u\n", ipa_ctx->stats.tx_sw_pkts, ipa_ctx->stats.tx_hw_pkts, ipa_ctx->stats.rx_pkts, Loading @@ -766,10 +764,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, ipa_ctx->stats.a2_power_off_reqs_in, ipa_ctx->stats.a2_power_off_reqs_out, ipa_ctx->stats.a2_power_modem_acks, ipa_ctx->stats.a2_power_apps_acks, ipa_ctx->stats.wlan_rx_pkts, ipa_ctx->stats.wlan_rx_comp, ipa_ctx->stats.wlan_tx_pkts); ipa_ctx->stats.a2_power_apps_acks); cnt += nbytes; for (i = 0; i < MAX_NUM_EXCP; i++) { Loading Loading @@ -800,6 +795,67 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } static ssize_t ipa_read_wstats(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { #define FRMT_STR "%25s %10u\n" #define FRMT_STR1 "%25s %10u\n\n" int cnt = 0; int nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx Pkts Rcvd:", ipa_ctx->wstats.rx_pkts_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx Pkts Status Rcvd:", ipa_ctx->wstats.rx_pkts_status_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Rcvd:", ipa_ctx->wstats.rx_hd_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Processed:", ipa_ctx->wstats.rx_hd_processed); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Sent Back:", ipa_ctx->wstats.rx_hd_reply); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR1, "Rx Pkt Leak:", ipa_ctx->wstats.rx_pkt_leak); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DP Fail:", ipa_ctx->wstats.rx_dp_fail); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Buf Total:", ipa_ctx->wlan_comm_cnt); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Buf Cnt:", ipa_ctx->wstats.tx_buf_cnt); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Pkts Sent:", ipa_ctx->wstats.tx_pkts_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Pkts Freed:", ipa_ctx->wstats.tx_pkts_freed); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Avail Fifo Desc:", ipa_ctx->ep[19].avail_fifo_desc); cnt += nbytes; return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } void _ipa_write_dbg_cnt_v1(int option) { if (option == 1) Loading Loading @@ -1021,12 +1077,6 @@ static ssize_t ipa_read_nat4(struct file *file, tmp++; value = *tmp; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "IP-CKSM-delta:0x%x ", (value & 0x0000FFFF)); cnt += nbytes; flag = ((value & 0xFFFF0000) >> 16); if (flag & NAT_ENTRY_RST_FIN_BIT) { nbytes = Loading Loading @@ -1174,6 +1224,10 @@ const struct file_operations ipa_stats_ops = { .read = ipa_read_stats, }; const struct file_operations ipa_wstats_ops = { .read = ipa_read_wstats, }; const struct file_operations ipa_msg_ops = { .read = ipa_read_msg, }; Loading Loading @@ -1276,6 +1330,13 @@ void ipa_debugfs_init(void) goto fail; } dfile_wstats = debugfs_create_file("wstats", read_only_mode, dent, 0, &ipa_wstats_ops); if (!dfile_wstats || IS_ERR(dfile_wstats)) { IPAERR("fail to create file for debug_fs wstats\n"); goto fail; } dfile_dbg_cnt = debugfs_create_file("dbg_cnt", read_write_mode, dent, 0, &ipa_dbg_cnt_ops); if (!dfile_dbg_cnt || IS_ERR(dfile_dbg_cnt)) { Loading drivers/platform/msm/ipa/ipa_dp.c +255 −173 Original line number Diff line number Diff line Loading @@ -36,16 +36,25 @@ * part of the data buffer */ #define IPA_LAN_RX_BUFF_SZ 7936 #define IPA_WLAN_RX_POOL_SZ 16 #define IPA_WLAN_RX_BUFF_SZ 2048 #define IPA_WLAN_COMM_RX_POOL_LOW 100 #define IPA_WLAN_COMM_RX_POOL_HIGH 900 static struct sk_buff *ipa_get_skb_ipa_rx(unsigned int len, gfp_t flags); static void ipa_replenish_wlan_rx_cache(struct ipa_sys_context *sys); static void ipa_replenish_rx_cache(struct ipa_sys_context *sys); static void replenish_rx_work_func(struct work_struct *work); static void ipa_wq_handle_rx(struct work_struct *work); static void ipa_wq_handle_tx(struct work_struct *work); static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size); static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size); static int ipa_assign_policy(struct ipa_sys_connect_params *in, struct ipa_sys_context *sys); static void ipa_cleanup_rx(struct ipa_sys_context *sys); static void ipa_wq_rx_avail(struct work_struct *work); static void ipa_allocate_wlan_rx_common_cache(u32 size); static void ipa_wq_write_done_common(struct ipa_sys_context *sys, u32 cnt) { Loading Loading @@ -708,7 +717,15 @@ static int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all, if (iov.addr == 0) break; if (sys->ep->client == IPA_CLIENT_WLAN1_CONS || sys->ep->client == IPA_CLIENT_WLAN2_CONS || sys->ep->client == IPA_CLIENT_WLAN3_CONS || sys->ep->client == IPA_CLIENT_WLAN4_CONS) { ipa_wlan_wq_rx_common(sys, iov.size); } else ipa_wq_rx_common(sys, iov.size); cnt++; }; Loading Loading @@ -940,7 +957,8 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep->client_notify = sys_in->notify; ep->priv = sys_in->priv; ep->sys->ep = ep; ep->avail_fifo_desc = (sys_in->desc_fifo_sz/sizeof(struct sps_iovec)); ep->avail_fifo_desc = ((sys_in->desc_fifo_sz/sizeof(struct sps_iovec))-1); INIT_LIST_HEAD(&ep->sys->head_desc_list); spin_lock_init(&ep->sys->spinlock); Loading Loading @@ -1020,6 +1038,12 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) if (IPA_CLIENT_IS_CONS(sys_in->client)) ipa_replenish_rx_cache(ep->sys); if (sys_in->client == IPA_CLIENT_WLAN1_CONS || sys_in->client == IPA_CLIENT_WLAN2_CONS || sys_in->client == IPA_CLIENT_WLAN3_CONS || sys_in->client == IPA_CLIENT_WLAN4_CONS) { ipa_allocate_wlan_rx_common_cache(IPA_WLAN_COMM_RX_POOL_LOW); } IPADBG("client %d (ep: %d) connected sys=%p\n", sys_in->client, ipa_ep_idx, ep->sys); Loading Loading @@ -1231,6 +1255,120 @@ static void ipa_wq_handle_rx(struct work_struct *work) ipa_handle_rx(sys); } static void ipa_replenish_wlan_rx_cache(struct ipa_sys_context *sys) { struct ipa_rx_pkt_wrapper *rx_pkt = NULL; struct ipa_rx_pkt_wrapper *tmp; int ret; u32 rx_len_cached = 0; IPADBG("\n"); spin_lock(&ipa_ctx->wlan_spinlock); rx_len_cached = sys->len; if (rx_len_cached < sys->rx_pool_sz) { list_for_each_entry_safe(rx_pkt, tmp, &ipa_ctx->wlan_comm_desc_list, link) { list_del(&rx_pkt->link); if (ipa_ctx->wstats.tx_buf_cnt > 0) ipa_ctx->wstats.tx_buf_cnt--; INIT_LIST_HEAD(&rx_pkt->link); rx_pkt->len = 0; rx_pkt->sys = sys; ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, IPA_WLAN_RX_BUFF_SZ, rx_pkt, 0); if (ret) { IPAERR("sps_transfer_one failed %d\n", ret); goto fail_sps_transfer; } list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; if (rx_len_cached >= sys->rx_pool_sz) { spin_unlock(&ipa_ctx->wlan_spinlock); return; } } } spin_unlock(&ipa_ctx->wlan_spinlock); if (rx_len_cached < sys->rx_pool_sz && ipa_ctx->wlan_comm_cnt < IPA_WLAN_COMM_RX_POOL_HIGH) { ipa_replenish_rx_cache(sys); ipa_ctx->wlan_comm_cnt += (sys->rx_pool_sz - rx_len_cached); } return; fail_sps_transfer: list_del(&rx_pkt->link); spin_unlock(&ipa_ctx->wlan_spinlock); return; } static void ipa_allocate_wlan_rx_common_cache(u32 size) { void *ptr; struct ipa_rx_pkt_wrapper *rx_pkt; int rx_len_cached = 0; gfp_t flag = GFP_NOWAIT | __GFP_NOWARN; rx_len_cached = ipa_ctx->wlan_comm_cnt; while (rx_len_cached < size) { rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache, flag); if (!rx_pkt) { IPAERR("failed to alloc rx wrapper\n"); goto fail_kmem_cache_alloc; } INIT_LIST_HEAD(&rx_pkt->link); INIT_WORK(&rx_pkt->work, ipa_wq_rx_avail); rx_pkt->data.skb = ipa_get_skb_ipa_rx(IPA_WLAN_RX_BUFF_SZ, flag); if (rx_pkt->data.skb == NULL) { IPAERR("failed to alloc skb\n"); goto fail_skb_alloc; } ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ); rx_pkt->data.dma_addr = dma_map_single(NULL, ptr, IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE); if (rx_pkt->data.dma_addr == 0 || rx_pkt->data.dma_addr == ~0) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; } list_add_tail(&rx_pkt->link, &ipa_ctx->wlan_comm_desc_list); rx_len_cached = ++ipa_ctx->wlan_comm_cnt; ipa_ctx->wstats.tx_buf_cnt++; } return; fail_dma_mapping: dev_kfree_skb_any(rx_pkt->data.skb); fail_skb_alloc: kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); fail_kmem_cache_alloc: return; } /** * ipa_replenish_rx_cache() - Replenish the Rx packets cache. * Loading Loading @@ -1267,26 +1405,27 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) INIT_WORK(&rx_pkt->work, ipa_wq_rx_avail); rx_pkt->sys = sys; rx_pkt->skb = sys->get_skb(sys->rx_buff_sz, flag); if (rx_pkt->skb == NULL) { rx_pkt->data.skb = sys->get_skb(sys->rx_buff_sz, flag); if (rx_pkt->data.skb == NULL) { IPAERR("failed to alloc skb\n"); goto fail_skb_alloc; } ptr = skb_put(rx_pkt->skb, sys->rx_buff_sz); rx_pkt->dma_address = dma_map_single(NULL, ptr, ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz); rx_pkt->data.dma_addr = dma_map_single(NULL, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); if (rx_pkt->dma_address == 0 || rx_pkt->dma_address == ~0) { if (rx_pkt->data.dma_addr == 0 || rx_pkt->data.dma_addr == ~0) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->dma_address, ptr); (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; } list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->dma_address, sys->rx_buff_sz, rx_pkt, 0); ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0); if (ret) { IPAERR("sps_transfer_one failed %d\n", ret); Loading @@ -1299,10 +1438,10 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) fail_sps_transfer: list_del(&rx_pkt->link); rx_len_cached = --sys->len; dma_unmap_single(NULL, rx_pkt->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); dma_unmap_single(NULL, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); fail_dma_mapping: sys->free_skb(rx_pkt->skb); sys->free_skb(rx_pkt->data.skb); fail_skb_alloc: kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); fail_kmem_cache_alloc: Loading Loading @@ -1332,136 +1471,13 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys) list_for_each_entry_safe(rx_pkt, r, &sys->head_desc_list, link) { list_del(&rx_pkt->link); dma_unmap_single(NULL, rx_pkt->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); sys->free_skb(rx_pkt->skb); dma_unmap_single(NULL, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); sys->free_skb(rx_pkt->data.skb); kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); } } static int ipa_wlan_rx_pyld_hdlr(struct sk_buff *skb, struct ipa_sys_context *sys) { int rc = 0; struct ipa_hw_pkt_status *status; struct sk_buff *skb2; int pad_len_byte; int len; IPADBG("\n"); IPA_DUMP_BUFF(skb->data, 0, skb->len); if (skb->len == 0) { IPAERR("ZLT\n"); sys->free_skb(skb); return rc; } while (skb->len) { IPADBG("LEN_REM %d\n", skb->len); if (skb->len < IPA_PKT_STATUS_SIZE) { IPAERR("status straddles buffer, not supported\n"); sys->free_skb(skb); return rc; } status = (struct ipa_hw_pkt_status *)skb->data; IPADBG("STATUS opcode=%d src=%d dst=%d len=%d\n", status->status_opcode, status->endp_src_idx, status->endp_dest_idx, status->pkt_len); if (status->status_opcode != IPA_HW_STATUS_OPCODE_PACKET) { IPAERR("unsupported opcode\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } if (status->endp_dest_idx >= IPA_NUM_PIPES || status->endp_src_idx >= IPA_NUM_PIPES || status->pkt_len > IPA_GENERIC_AGGR_BYTE_LIMIT * 1024) { IPAERR( "status fields invalid endp_dest_idx:%d endp_src_idx:%d pkt_len:%d\n", status->endp_dest_idx, status->endp_src_idx, status->pkt_len); BUG(); } /* Not sure what is this */ if (status->pkt_len == 0) { IPADBG("Skip aggr close status\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } if (status->endp_dest_idx == (sys->ep - ipa_ctx->ep)) { /* RX data */ if (skb->len == IPA_PKT_STATUS_SIZE) { IPAERR("Only status packet, not expected\n"); sys->free_skb(skb); return rc; } if (sys->ep->cfg.hdr_ext.hdr_total_len_or_pad_valid) { IPADBG("padding is set\n"); pad_len_byte = *(u8 *)(status+1); len = status->pkt_len + (pad_len_byte & 0x3f); } else { IPADBG("padding is not set\n"); pad_len_byte = 0; len = status->pkt_len; } IPADBG("pad_byte:0x%x pkt_len:%d len:%d\n", pad_len_byte, status->pkt_len, len); skb2 = skb_clone(skb, GFP_KERNEL); if (likely(skb2)) { if (skb->len < len) { IPAERR( "Pkt straddles across buf skb_len:%d len:%d\n", skb->len, len); skb_pull(skb, skb->len); } else { IPADBG("rx avail for %d\n", status->endp_dest_idx); skb_trim(skb2, status->pkt_len + IPA_PKT_STATUS_SIZE); skb_pull(skb2, IPA_PKT_STATUS_SIZE); IPADBG("skb2 len bfr clnt notify %d\n", skb2->len); sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, (unsigned long)(skb2)); ipa_ctx->stats.wlan_tx_pkts++; skb_pull(skb, len + IPA_PKT_STATUS_SIZE); IPADBG("skb len aftr cur pk pull:%d\n", skb->len); } } else { IPAERR("fail to clone\n"); if (skb->len < len) { IPAERR( "Pkt straddles across buf skb_len:%d len:%d\n", skb->len, len); skb_pull(skb, skb->len); } else { skb_pull(skb, len + IPA_PKT_STATUS_SIZE); } } } else { IPAERR("tx completion not expected for %d\n", status->endp_src_idx); skb_pull(skb, IPA_PKT_STATUS_SIZE); } }; sys->free_skb(skb); return rc; } static int ipa_lan_rx_pyld_hdlr(struct sk_buff *skb, struct ipa_sys_context *sys) Loading Loading @@ -1929,9 +1945,9 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) sys->len--; if (size) rx_pkt_expected->len = size; rx_skb = rx_pkt_expected->skb; dma_unmap_single(NULL, rx_pkt_expected->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); rx_skb = rx_pkt_expected->data.skb; dma_unmap_single(NULL, rx_pkt_expected->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); rx_skb->tail = rx_skb->data + rx_pkt_expected->len; rx_skb->len = rx_pkt_expected->len; rx_skb->truesize = rx_pkt_expected->len + sizeof(struct sk_buff); Loading @@ -1939,7 +1955,38 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) ipa_replenish_rx_cache(sys); kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt_expected); } static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size) { struct ipa_rx_pkt_wrapper *rx_pkt_expected; struct sk_buff *rx_skb; if (unlikely(list_empty(&sys->head_desc_list))) { WARN_ON(1); return; } rx_pkt_expected = list_first_entry(&sys->head_desc_list, struct ipa_rx_pkt_wrapper, link); list_del(&rx_pkt_expected->link); sys->len--; if (size) rx_pkt_expected->len = size; rx_skb = rx_pkt_expected->data.skb; rx_skb->tail = rx_skb->data + rx_pkt_expected->len; rx_skb->len = rx_pkt_expected->len; rx_skb->truesize = rx_pkt_expected->len + sizeof(struct sk_buff); ipa_ctx->wstats.tx_pkts_rcvd++; sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, (unsigned long)(&rx_pkt_expected->data)); ipa_replenish_wlan_rx_cache(sys); } static void ipa_wq_rx_avail(struct work_struct *work) { Loading Loading @@ -2064,27 +2111,24 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, in->client == IPA_CLIENT_WLAN4_CONS) { IPADBG("assigning policy to client:%d", in->client); in->ipa_ep_cfg.status.status_en = false; sys->policy = IPA_POLICY_INTR_POLL_MODE; sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS | SPS_O_NO_DISABLE); sys->sps_callback = ipa_sps_irq_rx_notify; INIT_WORK(&sys->work, ipa_wq_handle_rx); INIT_DELAYED_WORK(&sys->switch_to_intr_work, switch_to_intr_rx_work_func); INIT_DELAYED_WORK(&sys->replenish_rx_work, replenish_rx_work_func); sys->rx_buff_sz = IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT * 1024; sys->rx_pool_sz = IPA_WLAN_GENERIC_RX_POOL_SZ; sys->pyld_hdlr = ipa_wlan_rx_pyld_hdlr; atomic_set(&sys->curr_polling_state, 0); sys->rx_buff_sz = IPA_WLAN_RX_BUFF_SZ; sys->rx_pool_sz = IPA_WLAN_RX_POOL_SZ; sys->pyld_hdlr = NULL; sys->get_skb = ipa_get_skb_ipa_rx; sys->free_skb = ipa_free_skb_rx; in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; in->ipa_ep_cfg.aggr.aggr = IPA_GENERIC; in->ipa_ep_cfg.aggr.aggr_byte_limit = ((IPA_WLAN_GENERIC_AGGR_RX_SIZE/1024)-1); in->ipa_ep_cfg.aggr.aggr_time_limit = IPA_GENERIC_AGGR_TIME_LIMIT; in->ipa_ep_cfg.aggr.aggr_pkt_limit = IPA_GENERIC_AGGR_PKT_LIMIT; IPADBG("aggr en:%d aggr_byte_limit:%d", in->ipa_ep_cfg.aggr.aggr_en, in->ipa_ep_cfg.aggr.aggr_byte_limit); IPADBG("aggr_pkt_limit:%d", in->ipa_ep_cfg.aggr.aggr_pkt_limit); in->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR; } else { IPAERR("Need to install a RX pipe hdlr\n"); WARN_ON(1); Loading Loading @@ -2116,26 +2160,43 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, static void ipa_tx_client_rx_notify_release(void *user1, void *user2) { struct ipa_tx_data_desc *dd = (struct ipa_tx_data_desc *)user1; struct ipa_tx_data_desc *entry; u32 ep_idx = (u32)user2; IPADBG("Received data desc anchor:%p\n", dd); list_for_each_entry(entry, &dd->link, link) { IPADBG("data desc=0x%p priv=0x%p ep=%d\n", entry, entry->priv, ep_idx); ipa_ctx->ep[ep_idx].avail_fifo_desc++; ipa_ctx->stats.wlan_rx_comp++; } ipa_ctx->wstats.rx_pkts_status_rcvd++; /* wlan host driver waits till tx complete before unload */ IPADBG("ep=%d fifo_desc_free_count=%d\n", ep_idx, ipa_ctx->ep[ep_idx].avail_fifo_desc); IPADBG("calling client notify callback with priv:%p\n", ipa_ctx->ep[ep_idx].priv); if (ipa_ctx->ep[ep_idx].client_notify) if (ipa_ctx->ep[ep_idx].client_notify) { ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv, IPA_WRITE_DONE, (unsigned long)user1); ipa_ctx->wstats.rx_hd_reply++; } } /** * ipa_tx_client_rx_pkt_status() - Callback function * which will call the user supplied callback function to * increase the available fifo descriptor * * @user1: [in] - Data Descriptor * @user2: [in] - endpoint idx * * This notified callback is for the destination client * This function is supplied in ipa_tx_dp_mul */ static void ipa_tx_client_rx_pkt_status(void *user1, void *user2) { u32 ep_idx = (u32)user2; ipa_ctx->ep[ep_idx].avail_fifo_desc++; ipa_ctx->wstats.rx_pkts_status_rcvd++; } Loading Loading @@ -2170,6 +2231,9 @@ int ipa_tx_dp_mul(enum ipa_client_type src, int ep_idx; IPADBG("Received data desc anchor:%p\n", data_desc); ipa_ctx->wstats.rx_hd_rcvd++; spin_lock(&ipa_ctx->ipa_tx_mul_spinlock); ep_idx = ipa_get_ep_mapping(src); if (unlikely(ep_idx == -1)) { Loading Loading @@ -2216,32 +2280,50 @@ int ipa_tx_dp_mul(enum ipa_client_type src, IPADBG("data desc:%p\n", data_desc); desc.callback = ipa_tx_client_rx_notify_release; } else { desc.callback = NULL; desc.callback = ipa_tx_client_rx_pkt_status; } IPADBG("calling ipa_send_one()\n"); if (ipa_send_one(sys, &desc, true)) { IPAERR("fail to send skb\n"); ipa_ctx->wstats.rx_pkt_leak += (cnt-1); ipa_ctx->wstats.rx_dp_fail++; goto fail_send; } ipa_ctx->ep[ep_idx].avail_fifo_desc--; ipa_ctx->stats.wlan_rx_pkts++; ipa_ctx->wstats.rx_pkts_rcvd++; IPADBG("ep=%d fifo desc=%d\n", ep_idx, ipa_ctx->ep[ep_idx].avail_fifo_desc); } ipa_ctx->wstats.rx_hd_processed++; spin_unlock(&ipa_ctx->ipa_tx_mul_spinlock); return 0; fail_send: spin_unlock(&ipa_ctx->ipa_tx_mul_spinlock); return -EFAULT; } EXPORT_SYMBOL(ipa_tx_dp_mul); void ipa_free_skb(struct sk_buff *skb) void ipa_free_skb(struct ipa_rx_data *data) { dev_kfree_skb_any(skb); struct ipa_rx_pkt_wrapper *rx_pkt; spin_lock(&ipa_ctx->wlan_spinlock); ipa_ctx->wstats.tx_pkts_freed++; rx_pkt = container_of(data, struct ipa_rx_pkt_wrapper, data); ipa_skb_recycle(rx_pkt->data.skb); (void)skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ); list_add_tail(&rx_pkt->link, &ipa_ctx->wlan_comm_desc_list); ipa_ctx->wstats.tx_buf_cnt++; spin_unlock(&ipa_ctx->wlan_spinlock); } EXPORT_SYMBOL(ipa_free_skb); drivers/platform/msm/ipa/ipa_i.h +23 −18 Original line number Diff line number Diff line Loading @@ -49,18 +49,6 @@ #define WLAN3_CONS_RX_EP 17 #define WLAN4_CONS_RX_EP 18 #define IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT 32 #define IPA_WLAN_GENERIC_RX_POOL_SZ 4 #define IPA_WLAN_HDR_SIZE 26 #define IPA_WLAN_PADDING_BYTES 2 #define IPA_IP_PKT_SIZE 1500 #define IPA_WLAN_GENERIC_AGGR_RX_SIZE \ ((IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT * 1024) - \ IPA_PKT_STATUS_SIZE - IPA_WLAN_HDR_SIZE - \ IPA_WLAN_PADDING_BYTES - IPA_IP_PKT_SIZE) #define MAX_NUM_EXCP 8 #define MAX_NUM_IMM_CMD 20 Loading Loading @@ -480,9 +468,8 @@ struct ipa_desc { * @len: how many bytes are copied into skb's flat buffer */ struct ipa_rx_pkt_wrapper { struct sk_buff *skb; dma_addr_t dma_address; struct list_head link; struct ipa_rx_data data; u32 len; struct work_struct work; struct ipa_sys_context *sys; Loading Loading @@ -582,11 +569,22 @@ struct ipa_stats { u32 a2_power_off_reqs_out; u32 a2_power_modem_acks; u32 a2_power_apps_acks; u32 wlan_rx_pkts; u32 wlan_rx_comp; u32 wlan_tx_pkts; }; struct ipa_wlan_stats { u32 rx_pkts_rcvd; u32 rx_pkts_status_rcvd; u32 rx_hd_processed; u32 rx_hd_reply; u32 rx_hd_rcvd; u32 rx_pkt_leak; u32 rx_dp_fail; u32 tx_buf_cnt; u32 tx_pkts_freed; u32 tx_pkts_rcvd; }; struct ipa_controller; /** Loading Loading @@ -718,6 +716,13 @@ struct ipa_context { void *smem_pipe_mem; u32 ipa_bus_hdl; struct ipa_controller *ctrl; /* wlan related member */ spinlock_t wlan_spinlock; spinlock_t ipa_tx_mul_spinlock; u32 wlan_comm_cnt; struct list_head wlan_comm_desc_list; struct ipa_wlan_stats wstats; }; /** Loading Loading @@ -959,6 +964,6 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, const struct ipa_rule_attrib *attrib, struct ipa_ipfltri_rule_eq *eq_attrib); void ipa_skb_recycle(struct sk_buff *skb); #endif /* _IPA_I_H_ */ Loading
arch/arm/mach-msm/include/mach/ipa.h +13 −2 Original line number Diff line number Diff line Loading @@ -678,6 +678,17 @@ struct ipa_tx_data_desc { u16 pyld_len; }; /** * struct ipa_rx_data - information needed * to send to wlan driver on receiving data from ipa hw * @skb: skb * @dma_addr: DMA address of this Rx packet */ struct ipa_rx_data { struct sk_buff *skb; dma_addr_t dma_addr; }; #ifdef CONFIG_IPA /* Loading Loading @@ -833,7 +844,7 @@ int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, int ipa_tx_dp_mul(enum ipa_client_type dst, struct ipa_tx_data_desc *data_desc); void ipa_free_skb(struct sk_buff *); void ipa_free_skb(struct ipa_rx_data *); /* * System pipes Loading Loading @@ -1285,7 +1296,7 @@ static inline int ipa_tx_dp_mul( return -EPERM; } static inline void ipa_free_skb(struct sk_buff *skb) static inline void ipa_free_skb(struct ipa_rx_data *rx_in) { return; } Loading
drivers/platform/msm/ipa/ipa.c +6 −0 Original line number Diff line number Diff line Loading @@ -1976,6 +1976,12 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, mutex_init(&ipa_ctx->ipa_active_clients_lock); ipa_ctx->ipa_active_clients = 0; /* wlan related member */ spin_lock_init(&ipa_ctx->wlan_spinlock); spin_lock_init(&ipa_ctx->ipa_tx_mul_spinlock); ipa_ctx->wlan_comm_cnt = 0; INIT_LIST_HEAD(&ipa_ctx->wlan_comm_desc_list); memset(&ipa_ctx->wstats, 0, sizeof(struct ipa_wlan_stats)); /* enable IPA clocks until the end of the initialization */ ipa_inc_client_enable_clks(); Loading
drivers/platform/msm/ipa/ipa_debugfs.c +75 −14 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ static struct dentry *dfile_ip6_rt; static struct dentry *dfile_ip4_flt; static struct dentry *dfile_ip6_flt; static struct dentry *dfile_stats; static struct dentry *dfile_wstats; static struct dentry *dfile_dbg_cnt; static struct dentry *dfile_msg; static struct dentry *dfile_ip4_nat; Loading Loading @@ -748,10 +749,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, "a2_power_off_reqs_in=%u\n" "a2_power_off_reqs_out=%u\n" "a2_power_modem_acks=%u\n" "a2_power_apps_acks=%u\n" "wlan_rx_pkts=%u\n" "wlan_rx_comp=%u\n" "wlan_tx_pkts=%u\n", "a2_power_apps_acks=%u\n", ipa_ctx->stats.tx_sw_pkts, ipa_ctx->stats.tx_hw_pkts, ipa_ctx->stats.rx_pkts, Loading @@ -766,10 +764,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, ipa_ctx->stats.a2_power_off_reqs_in, ipa_ctx->stats.a2_power_off_reqs_out, ipa_ctx->stats.a2_power_modem_acks, ipa_ctx->stats.a2_power_apps_acks, ipa_ctx->stats.wlan_rx_pkts, ipa_ctx->stats.wlan_rx_comp, ipa_ctx->stats.wlan_tx_pkts); ipa_ctx->stats.a2_power_apps_acks); cnt += nbytes; for (i = 0; i < MAX_NUM_EXCP; i++) { Loading Loading @@ -800,6 +795,67 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } static ssize_t ipa_read_wstats(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { #define FRMT_STR "%25s %10u\n" #define FRMT_STR1 "%25s %10u\n\n" int cnt = 0; int nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx Pkts Rcvd:", ipa_ctx->wstats.rx_pkts_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx Pkts Status Rcvd:", ipa_ctx->wstats.rx_pkts_status_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Rcvd:", ipa_ctx->wstats.rx_hd_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Processed:", ipa_ctx->wstats.rx_hd_processed); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DH Sent Back:", ipa_ctx->wstats.rx_hd_reply); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR1, "Rx Pkt Leak:", ipa_ctx->wstats.rx_pkt_leak); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Rx DP Fail:", ipa_ctx->wstats.rx_dp_fail); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Buf Total:", ipa_ctx->wlan_comm_cnt); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Buf Cnt:", ipa_ctx->wstats.tx_buf_cnt); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Pkts Sent:", ipa_ctx->wstats.tx_pkts_rcvd); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Tx Pkts Freed:", ipa_ctx->wstats.tx_pkts_freed); cnt += nbytes; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR, "Avail Fifo Desc:", ipa_ctx->ep[19].avail_fifo_desc); cnt += nbytes; return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } void _ipa_write_dbg_cnt_v1(int option) { if (option == 1) Loading Loading @@ -1021,12 +1077,6 @@ static ssize_t ipa_read_nat4(struct file *file, tmp++; value = *tmp; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "IP-CKSM-delta:0x%x ", (value & 0x0000FFFF)); cnt += nbytes; flag = ((value & 0xFFFF0000) >> 16); if (flag & NAT_ENTRY_RST_FIN_BIT) { nbytes = Loading Loading @@ -1174,6 +1224,10 @@ const struct file_operations ipa_stats_ops = { .read = ipa_read_stats, }; const struct file_operations ipa_wstats_ops = { .read = ipa_read_wstats, }; const struct file_operations ipa_msg_ops = { .read = ipa_read_msg, }; Loading Loading @@ -1276,6 +1330,13 @@ void ipa_debugfs_init(void) goto fail; } dfile_wstats = debugfs_create_file("wstats", read_only_mode, dent, 0, &ipa_wstats_ops); if (!dfile_wstats || IS_ERR(dfile_wstats)) { IPAERR("fail to create file for debug_fs wstats\n"); goto fail; } dfile_dbg_cnt = debugfs_create_file("dbg_cnt", read_write_mode, dent, 0, &ipa_dbg_cnt_ops); if (!dfile_dbg_cnt || IS_ERR(dfile_dbg_cnt)) { Loading
drivers/platform/msm/ipa/ipa_dp.c +255 −173 Original line number Diff line number Diff line Loading @@ -36,16 +36,25 @@ * part of the data buffer */ #define IPA_LAN_RX_BUFF_SZ 7936 #define IPA_WLAN_RX_POOL_SZ 16 #define IPA_WLAN_RX_BUFF_SZ 2048 #define IPA_WLAN_COMM_RX_POOL_LOW 100 #define IPA_WLAN_COMM_RX_POOL_HIGH 900 static struct sk_buff *ipa_get_skb_ipa_rx(unsigned int len, gfp_t flags); static void ipa_replenish_wlan_rx_cache(struct ipa_sys_context *sys); static void ipa_replenish_rx_cache(struct ipa_sys_context *sys); static void replenish_rx_work_func(struct work_struct *work); static void ipa_wq_handle_rx(struct work_struct *work); static void ipa_wq_handle_tx(struct work_struct *work); static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size); static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size); static int ipa_assign_policy(struct ipa_sys_connect_params *in, struct ipa_sys_context *sys); static void ipa_cleanup_rx(struct ipa_sys_context *sys); static void ipa_wq_rx_avail(struct work_struct *work); static void ipa_allocate_wlan_rx_common_cache(u32 size); static void ipa_wq_write_done_common(struct ipa_sys_context *sys, u32 cnt) { Loading Loading @@ -708,7 +717,15 @@ static int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all, if (iov.addr == 0) break; if (sys->ep->client == IPA_CLIENT_WLAN1_CONS || sys->ep->client == IPA_CLIENT_WLAN2_CONS || sys->ep->client == IPA_CLIENT_WLAN3_CONS || sys->ep->client == IPA_CLIENT_WLAN4_CONS) { ipa_wlan_wq_rx_common(sys, iov.size); } else ipa_wq_rx_common(sys, iov.size); cnt++; }; Loading Loading @@ -940,7 +957,8 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep->client_notify = sys_in->notify; ep->priv = sys_in->priv; ep->sys->ep = ep; ep->avail_fifo_desc = (sys_in->desc_fifo_sz/sizeof(struct sps_iovec)); ep->avail_fifo_desc = ((sys_in->desc_fifo_sz/sizeof(struct sps_iovec))-1); INIT_LIST_HEAD(&ep->sys->head_desc_list); spin_lock_init(&ep->sys->spinlock); Loading Loading @@ -1020,6 +1038,12 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) if (IPA_CLIENT_IS_CONS(sys_in->client)) ipa_replenish_rx_cache(ep->sys); if (sys_in->client == IPA_CLIENT_WLAN1_CONS || sys_in->client == IPA_CLIENT_WLAN2_CONS || sys_in->client == IPA_CLIENT_WLAN3_CONS || sys_in->client == IPA_CLIENT_WLAN4_CONS) { ipa_allocate_wlan_rx_common_cache(IPA_WLAN_COMM_RX_POOL_LOW); } IPADBG("client %d (ep: %d) connected sys=%p\n", sys_in->client, ipa_ep_idx, ep->sys); Loading Loading @@ -1231,6 +1255,120 @@ static void ipa_wq_handle_rx(struct work_struct *work) ipa_handle_rx(sys); } static void ipa_replenish_wlan_rx_cache(struct ipa_sys_context *sys) { struct ipa_rx_pkt_wrapper *rx_pkt = NULL; struct ipa_rx_pkt_wrapper *tmp; int ret; u32 rx_len_cached = 0; IPADBG("\n"); spin_lock(&ipa_ctx->wlan_spinlock); rx_len_cached = sys->len; if (rx_len_cached < sys->rx_pool_sz) { list_for_each_entry_safe(rx_pkt, tmp, &ipa_ctx->wlan_comm_desc_list, link) { list_del(&rx_pkt->link); if (ipa_ctx->wstats.tx_buf_cnt > 0) ipa_ctx->wstats.tx_buf_cnt--; INIT_LIST_HEAD(&rx_pkt->link); rx_pkt->len = 0; rx_pkt->sys = sys; ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, IPA_WLAN_RX_BUFF_SZ, rx_pkt, 0); if (ret) { IPAERR("sps_transfer_one failed %d\n", ret); goto fail_sps_transfer; } list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; if (rx_len_cached >= sys->rx_pool_sz) { spin_unlock(&ipa_ctx->wlan_spinlock); return; } } } spin_unlock(&ipa_ctx->wlan_spinlock); if (rx_len_cached < sys->rx_pool_sz && ipa_ctx->wlan_comm_cnt < IPA_WLAN_COMM_RX_POOL_HIGH) { ipa_replenish_rx_cache(sys); ipa_ctx->wlan_comm_cnt += (sys->rx_pool_sz - rx_len_cached); } return; fail_sps_transfer: list_del(&rx_pkt->link); spin_unlock(&ipa_ctx->wlan_spinlock); return; } static void ipa_allocate_wlan_rx_common_cache(u32 size) { void *ptr; struct ipa_rx_pkt_wrapper *rx_pkt; int rx_len_cached = 0; gfp_t flag = GFP_NOWAIT | __GFP_NOWARN; rx_len_cached = ipa_ctx->wlan_comm_cnt; while (rx_len_cached < size) { rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache, flag); if (!rx_pkt) { IPAERR("failed to alloc rx wrapper\n"); goto fail_kmem_cache_alloc; } INIT_LIST_HEAD(&rx_pkt->link); INIT_WORK(&rx_pkt->work, ipa_wq_rx_avail); rx_pkt->data.skb = ipa_get_skb_ipa_rx(IPA_WLAN_RX_BUFF_SZ, flag); if (rx_pkt->data.skb == NULL) { IPAERR("failed to alloc skb\n"); goto fail_skb_alloc; } ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ); rx_pkt->data.dma_addr = dma_map_single(NULL, ptr, IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE); if (rx_pkt->data.dma_addr == 0 || rx_pkt->data.dma_addr == ~0) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; } list_add_tail(&rx_pkt->link, &ipa_ctx->wlan_comm_desc_list); rx_len_cached = ++ipa_ctx->wlan_comm_cnt; ipa_ctx->wstats.tx_buf_cnt++; } return; fail_dma_mapping: dev_kfree_skb_any(rx_pkt->data.skb); fail_skb_alloc: kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); fail_kmem_cache_alloc: return; } /** * ipa_replenish_rx_cache() - Replenish the Rx packets cache. * Loading Loading @@ -1267,26 +1405,27 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) INIT_WORK(&rx_pkt->work, ipa_wq_rx_avail); rx_pkt->sys = sys; rx_pkt->skb = sys->get_skb(sys->rx_buff_sz, flag); if (rx_pkt->skb == NULL) { rx_pkt->data.skb = sys->get_skb(sys->rx_buff_sz, flag); if (rx_pkt->data.skb == NULL) { IPAERR("failed to alloc skb\n"); goto fail_skb_alloc; } ptr = skb_put(rx_pkt->skb, sys->rx_buff_sz); rx_pkt->dma_address = dma_map_single(NULL, ptr, ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz); rx_pkt->data.dma_addr = dma_map_single(NULL, ptr, sys->rx_buff_sz, DMA_FROM_DEVICE); if (rx_pkt->dma_address == 0 || rx_pkt->dma_address == ~0) { if (rx_pkt->data.dma_addr == 0 || rx_pkt->data.dma_addr == ~0) { IPAERR("dma_map_single failure %p for %p\n", (void *)rx_pkt->dma_address, ptr); (void *)rx_pkt->data.dma_addr, ptr); goto fail_dma_mapping; } list_add_tail(&rx_pkt->link, &sys->head_desc_list); rx_len_cached = ++sys->len; ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->dma_address, sys->rx_buff_sz, rx_pkt, 0); ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->data.dma_addr, sys->rx_buff_sz, rx_pkt, 0); if (ret) { IPAERR("sps_transfer_one failed %d\n", ret); Loading @@ -1299,10 +1438,10 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys) fail_sps_transfer: list_del(&rx_pkt->link); rx_len_cached = --sys->len; dma_unmap_single(NULL, rx_pkt->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); dma_unmap_single(NULL, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); fail_dma_mapping: sys->free_skb(rx_pkt->skb); sys->free_skb(rx_pkt->data.skb); fail_skb_alloc: kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); fail_kmem_cache_alloc: Loading Loading @@ -1332,136 +1471,13 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys) list_for_each_entry_safe(rx_pkt, r, &sys->head_desc_list, link) { list_del(&rx_pkt->link); dma_unmap_single(NULL, rx_pkt->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); sys->free_skb(rx_pkt->skb); dma_unmap_single(NULL, rx_pkt->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); sys->free_skb(rx_pkt->data.skb); kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt); } } static int ipa_wlan_rx_pyld_hdlr(struct sk_buff *skb, struct ipa_sys_context *sys) { int rc = 0; struct ipa_hw_pkt_status *status; struct sk_buff *skb2; int pad_len_byte; int len; IPADBG("\n"); IPA_DUMP_BUFF(skb->data, 0, skb->len); if (skb->len == 0) { IPAERR("ZLT\n"); sys->free_skb(skb); return rc; } while (skb->len) { IPADBG("LEN_REM %d\n", skb->len); if (skb->len < IPA_PKT_STATUS_SIZE) { IPAERR("status straddles buffer, not supported\n"); sys->free_skb(skb); return rc; } status = (struct ipa_hw_pkt_status *)skb->data; IPADBG("STATUS opcode=%d src=%d dst=%d len=%d\n", status->status_opcode, status->endp_src_idx, status->endp_dest_idx, status->pkt_len); if (status->status_opcode != IPA_HW_STATUS_OPCODE_PACKET) { IPAERR("unsupported opcode\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } if (status->endp_dest_idx >= IPA_NUM_PIPES || status->endp_src_idx >= IPA_NUM_PIPES || status->pkt_len > IPA_GENERIC_AGGR_BYTE_LIMIT * 1024) { IPAERR( "status fields invalid endp_dest_idx:%d endp_src_idx:%d pkt_len:%d\n", status->endp_dest_idx, status->endp_src_idx, status->pkt_len); BUG(); } /* Not sure what is this */ if (status->pkt_len == 0) { IPADBG("Skip aggr close status\n"); skb_pull(skb, IPA_PKT_STATUS_SIZE); continue; } if (status->endp_dest_idx == (sys->ep - ipa_ctx->ep)) { /* RX data */ if (skb->len == IPA_PKT_STATUS_SIZE) { IPAERR("Only status packet, not expected\n"); sys->free_skb(skb); return rc; } if (sys->ep->cfg.hdr_ext.hdr_total_len_or_pad_valid) { IPADBG("padding is set\n"); pad_len_byte = *(u8 *)(status+1); len = status->pkt_len + (pad_len_byte & 0x3f); } else { IPADBG("padding is not set\n"); pad_len_byte = 0; len = status->pkt_len; } IPADBG("pad_byte:0x%x pkt_len:%d len:%d\n", pad_len_byte, status->pkt_len, len); skb2 = skb_clone(skb, GFP_KERNEL); if (likely(skb2)) { if (skb->len < len) { IPAERR( "Pkt straddles across buf skb_len:%d len:%d\n", skb->len, len); skb_pull(skb, skb->len); } else { IPADBG("rx avail for %d\n", status->endp_dest_idx); skb_trim(skb2, status->pkt_len + IPA_PKT_STATUS_SIZE); skb_pull(skb2, IPA_PKT_STATUS_SIZE); IPADBG("skb2 len bfr clnt notify %d\n", skb2->len); sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, (unsigned long)(skb2)); ipa_ctx->stats.wlan_tx_pkts++; skb_pull(skb, len + IPA_PKT_STATUS_SIZE); IPADBG("skb len aftr cur pk pull:%d\n", skb->len); } } else { IPAERR("fail to clone\n"); if (skb->len < len) { IPAERR( "Pkt straddles across buf skb_len:%d len:%d\n", skb->len, len); skb_pull(skb, skb->len); } else { skb_pull(skb, len + IPA_PKT_STATUS_SIZE); } } } else { IPAERR("tx completion not expected for %d\n", status->endp_src_idx); skb_pull(skb, IPA_PKT_STATUS_SIZE); } }; sys->free_skb(skb); return rc; } static int ipa_lan_rx_pyld_hdlr(struct sk_buff *skb, struct ipa_sys_context *sys) Loading Loading @@ -1929,9 +1945,9 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) sys->len--; if (size) rx_pkt_expected->len = size; rx_skb = rx_pkt_expected->skb; dma_unmap_single(NULL, rx_pkt_expected->dma_address, sys->rx_buff_sz, DMA_FROM_DEVICE); rx_skb = rx_pkt_expected->data.skb; dma_unmap_single(NULL, rx_pkt_expected->data.dma_addr, sys->rx_buff_sz, DMA_FROM_DEVICE); rx_skb->tail = rx_skb->data + rx_pkt_expected->len; rx_skb->len = rx_pkt_expected->len; rx_skb->truesize = rx_pkt_expected->len + sizeof(struct sk_buff); Loading @@ -1939,7 +1955,38 @@ static void ipa_wq_rx_common(struct ipa_sys_context *sys, u32 size) ipa_replenish_rx_cache(sys); kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt_expected); } static void ipa_wlan_wq_rx_common(struct ipa_sys_context *sys, u32 size) { struct ipa_rx_pkt_wrapper *rx_pkt_expected; struct sk_buff *rx_skb; if (unlikely(list_empty(&sys->head_desc_list))) { WARN_ON(1); return; } rx_pkt_expected = list_first_entry(&sys->head_desc_list, struct ipa_rx_pkt_wrapper, link); list_del(&rx_pkt_expected->link); sys->len--; if (size) rx_pkt_expected->len = size; rx_skb = rx_pkt_expected->data.skb; rx_skb->tail = rx_skb->data + rx_pkt_expected->len; rx_skb->len = rx_pkt_expected->len; rx_skb->truesize = rx_pkt_expected->len + sizeof(struct sk_buff); ipa_ctx->wstats.tx_pkts_rcvd++; sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, (unsigned long)(&rx_pkt_expected->data)); ipa_replenish_wlan_rx_cache(sys); } static void ipa_wq_rx_avail(struct work_struct *work) { Loading Loading @@ -2064,27 +2111,24 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, in->client == IPA_CLIENT_WLAN4_CONS) { IPADBG("assigning policy to client:%d", in->client); in->ipa_ep_cfg.status.status_en = false; sys->policy = IPA_POLICY_INTR_POLL_MODE; sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS | SPS_O_NO_DISABLE); sys->sps_callback = ipa_sps_irq_rx_notify; INIT_WORK(&sys->work, ipa_wq_handle_rx); INIT_DELAYED_WORK(&sys->switch_to_intr_work, switch_to_intr_rx_work_func); INIT_DELAYED_WORK(&sys->replenish_rx_work, replenish_rx_work_func); sys->rx_buff_sz = IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT * 1024; sys->rx_pool_sz = IPA_WLAN_GENERIC_RX_POOL_SZ; sys->pyld_hdlr = ipa_wlan_rx_pyld_hdlr; atomic_set(&sys->curr_polling_state, 0); sys->rx_buff_sz = IPA_WLAN_RX_BUFF_SZ; sys->rx_pool_sz = IPA_WLAN_RX_POOL_SZ; sys->pyld_hdlr = NULL; sys->get_skb = ipa_get_skb_ipa_rx; sys->free_skb = ipa_free_skb_rx; in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; in->ipa_ep_cfg.aggr.aggr = IPA_GENERIC; in->ipa_ep_cfg.aggr.aggr_byte_limit = ((IPA_WLAN_GENERIC_AGGR_RX_SIZE/1024)-1); in->ipa_ep_cfg.aggr.aggr_time_limit = IPA_GENERIC_AGGR_TIME_LIMIT; in->ipa_ep_cfg.aggr.aggr_pkt_limit = IPA_GENERIC_AGGR_PKT_LIMIT; IPADBG("aggr en:%d aggr_byte_limit:%d", in->ipa_ep_cfg.aggr.aggr_en, in->ipa_ep_cfg.aggr.aggr_byte_limit); IPADBG("aggr_pkt_limit:%d", in->ipa_ep_cfg.aggr.aggr_pkt_limit); in->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR; } else { IPAERR("Need to install a RX pipe hdlr\n"); WARN_ON(1); Loading Loading @@ -2116,26 +2160,43 @@ static int ipa_assign_policy(struct ipa_sys_connect_params *in, static void ipa_tx_client_rx_notify_release(void *user1, void *user2) { struct ipa_tx_data_desc *dd = (struct ipa_tx_data_desc *)user1; struct ipa_tx_data_desc *entry; u32 ep_idx = (u32)user2; IPADBG("Received data desc anchor:%p\n", dd); list_for_each_entry(entry, &dd->link, link) { IPADBG("data desc=0x%p priv=0x%p ep=%d\n", entry, entry->priv, ep_idx); ipa_ctx->ep[ep_idx].avail_fifo_desc++; ipa_ctx->stats.wlan_rx_comp++; } ipa_ctx->wstats.rx_pkts_status_rcvd++; /* wlan host driver waits till tx complete before unload */ IPADBG("ep=%d fifo_desc_free_count=%d\n", ep_idx, ipa_ctx->ep[ep_idx].avail_fifo_desc); IPADBG("calling client notify callback with priv:%p\n", ipa_ctx->ep[ep_idx].priv); if (ipa_ctx->ep[ep_idx].client_notify) if (ipa_ctx->ep[ep_idx].client_notify) { ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv, IPA_WRITE_DONE, (unsigned long)user1); ipa_ctx->wstats.rx_hd_reply++; } } /** * ipa_tx_client_rx_pkt_status() - Callback function * which will call the user supplied callback function to * increase the available fifo descriptor * * @user1: [in] - Data Descriptor * @user2: [in] - endpoint idx * * This notified callback is for the destination client * This function is supplied in ipa_tx_dp_mul */ static void ipa_tx_client_rx_pkt_status(void *user1, void *user2) { u32 ep_idx = (u32)user2; ipa_ctx->ep[ep_idx].avail_fifo_desc++; ipa_ctx->wstats.rx_pkts_status_rcvd++; } Loading Loading @@ -2170,6 +2231,9 @@ int ipa_tx_dp_mul(enum ipa_client_type src, int ep_idx; IPADBG("Received data desc anchor:%p\n", data_desc); ipa_ctx->wstats.rx_hd_rcvd++; spin_lock(&ipa_ctx->ipa_tx_mul_spinlock); ep_idx = ipa_get_ep_mapping(src); if (unlikely(ep_idx == -1)) { Loading Loading @@ -2216,32 +2280,50 @@ int ipa_tx_dp_mul(enum ipa_client_type src, IPADBG("data desc:%p\n", data_desc); desc.callback = ipa_tx_client_rx_notify_release; } else { desc.callback = NULL; desc.callback = ipa_tx_client_rx_pkt_status; } IPADBG("calling ipa_send_one()\n"); if (ipa_send_one(sys, &desc, true)) { IPAERR("fail to send skb\n"); ipa_ctx->wstats.rx_pkt_leak += (cnt-1); ipa_ctx->wstats.rx_dp_fail++; goto fail_send; } ipa_ctx->ep[ep_idx].avail_fifo_desc--; ipa_ctx->stats.wlan_rx_pkts++; ipa_ctx->wstats.rx_pkts_rcvd++; IPADBG("ep=%d fifo desc=%d\n", ep_idx, ipa_ctx->ep[ep_idx].avail_fifo_desc); } ipa_ctx->wstats.rx_hd_processed++; spin_unlock(&ipa_ctx->ipa_tx_mul_spinlock); return 0; fail_send: spin_unlock(&ipa_ctx->ipa_tx_mul_spinlock); return -EFAULT; } EXPORT_SYMBOL(ipa_tx_dp_mul); void ipa_free_skb(struct sk_buff *skb) void ipa_free_skb(struct ipa_rx_data *data) { dev_kfree_skb_any(skb); struct ipa_rx_pkt_wrapper *rx_pkt; spin_lock(&ipa_ctx->wlan_spinlock); ipa_ctx->wstats.tx_pkts_freed++; rx_pkt = container_of(data, struct ipa_rx_pkt_wrapper, data); ipa_skb_recycle(rx_pkt->data.skb); (void)skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ); list_add_tail(&rx_pkt->link, &ipa_ctx->wlan_comm_desc_list); ipa_ctx->wstats.tx_buf_cnt++; spin_unlock(&ipa_ctx->wlan_spinlock); } EXPORT_SYMBOL(ipa_free_skb);
drivers/platform/msm/ipa/ipa_i.h +23 −18 Original line number Diff line number Diff line Loading @@ -49,18 +49,6 @@ #define WLAN3_CONS_RX_EP 17 #define WLAN4_CONS_RX_EP 18 #define IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT 32 #define IPA_WLAN_GENERIC_RX_POOL_SZ 4 #define IPA_WLAN_HDR_SIZE 26 #define IPA_WLAN_PADDING_BYTES 2 #define IPA_IP_PKT_SIZE 1500 #define IPA_WLAN_GENERIC_AGGR_RX_SIZE \ ((IPA_WLAN_GENERIC_AGGR_BYTE_LIMIT * 1024) - \ IPA_PKT_STATUS_SIZE - IPA_WLAN_HDR_SIZE - \ IPA_WLAN_PADDING_BYTES - IPA_IP_PKT_SIZE) #define MAX_NUM_EXCP 8 #define MAX_NUM_IMM_CMD 20 Loading Loading @@ -480,9 +468,8 @@ struct ipa_desc { * @len: how many bytes are copied into skb's flat buffer */ struct ipa_rx_pkt_wrapper { struct sk_buff *skb; dma_addr_t dma_address; struct list_head link; struct ipa_rx_data data; u32 len; struct work_struct work; struct ipa_sys_context *sys; Loading Loading @@ -582,11 +569,22 @@ struct ipa_stats { u32 a2_power_off_reqs_out; u32 a2_power_modem_acks; u32 a2_power_apps_acks; u32 wlan_rx_pkts; u32 wlan_rx_comp; u32 wlan_tx_pkts; }; struct ipa_wlan_stats { u32 rx_pkts_rcvd; u32 rx_pkts_status_rcvd; u32 rx_hd_processed; u32 rx_hd_reply; u32 rx_hd_rcvd; u32 rx_pkt_leak; u32 rx_dp_fail; u32 tx_buf_cnt; u32 tx_pkts_freed; u32 tx_pkts_rcvd; }; struct ipa_controller; /** Loading Loading @@ -718,6 +716,13 @@ struct ipa_context { void *smem_pipe_mem; u32 ipa_bus_hdl; struct ipa_controller *ctrl; /* wlan related member */ spinlock_t wlan_spinlock; spinlock_t ipa_tx_mul_spinlock; u32 wlan_comm_cnt; struct list_head wlan_comm_desc_list; struct ipa_wlan_stats wstats; }; /** Loading Loading @@ -959,6 +964,6 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, const struct ipa_rule_attrib *attrib, struct ipa_ipfltri_rule_eq *eq_attrib); void ipa_skb_recycle(struct sk_buff *skb); #endif /* _IPA_I_H_ */