Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c6b3fe7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: WLAN data path optimization changes"

parents 6d52439a 7445690f
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -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

/*
@@ -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
@@ -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;
}
+6 −0
Original line number Diff line number Diff line
@@ -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();

+75 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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,
@@ -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++) {
@@ -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)
@@ -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 =
@@ -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,
};
@@ -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)) {
+255 −173
Original line number Diff line number Diff line
@@ -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)
{
@@ -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++;
	};

@@ -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);
@@ -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);
@@ -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.
 *
@@ -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);
@@ -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:
@@ -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)
@@ -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);
@@ -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)
{
@@ -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);
@@ -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++;
}


@@ -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)) {
@@ -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);
+23 −18
Original line number Diff line number Diff line
@@ -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

@@ -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;
@@ -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;

/**
@@ -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;
};

/**
@@ -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