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

Commit 02130724 authored by Chaitanya Pratapa's avatar Chaitanya Pratapa
Browse files

ipa: use common ring event ring for WLAN MCC pipes in auto config



In IPA4.0 Auto configuration, all event rings are allocated for
different use cases and if we use different event rings for WLAN
MCC pipes event ring allocation fails resulting in WLAN enablement
failure. Make changes to use common event ring for WLAN MCC pipes.

Change-Id: I46a462a4ad1a9135b1fd28fbc627eb49017a11e3
Signed-off-by: default avatarChaitanya Pratapa <cpratapa@codeaurora.org>
parent 38ef4c0c
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -944,6 +944,9 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl)
	__gsi_config_gen_irq(props->ee, ~0,
		~GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK);

	gsi_ctx->shared_ch_info.ch_id = gsi_ctx->max_ch;
	gsi_ctx->shared_ch_info.evchid = gsi_ctx->max_ev;

	gsi_writel(props->intr, gsi_ctx->base +
			GSI_EE_n_CNTXT_INTSET_OFFS(gsi_ctx->per.ee));

@@ -1801,7 +1804,8 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,

		if (atomic_read(
			&gsi_ctx->evtr[props->evt_ring_hdl].chan_ref_cnt) &&
			gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive) {
			gsi_ctx->evtr[props->evt_ring_hdl].props.exclusive &&
			!props->common_evt_ring) {
			GSIERR("evt ring=%lu exclusively used by chan_hdl=%p\n",
				props->evt_ring_hdl, chan_hdl);
			return -GSI_STATUS_UNSUPPORTED_OP;
@@ -1870,6 +1874,10 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl,
	ctx->user_data = user_data;
	*chan_hdl = props->ch_id;
	ctx->allocated = true;
	if ((props->evt_ring_hdl != ~0) && props->common_evt_ring) {
		gsi_ctx->shared_ch_info.ch_id = props->ch_id;
		gsi_ctx->shared_ch_info.evchid = props->evt_ring_hdl;
	}
	ctx->stats.dp.last_timestamp = jiffies_to_msecs(jiffies);
	atomic_inc(&gsi_ctx->num_chan);

@@ -2375,6 +2383,11 @@ int gsi_dealloc_channel(unsigned long chan_hdl)
		atomic_dec(&ctx->evtr->chan_ref_cnt);
	atomic_dec(&gsi_ctx->num_chan);

	if (gsi_ctx->shared_ch_info.ch_id == chan_hdl) {
		gsi_ctx->shared_ch_info.ch_id = gsi_ctx->max_ch;
		gsi_ctx->shared_ch_info.evchid = gsi_ctx->max_ev;
	}

	return GSI_STATUS_SUCCESS;
}
EXPORT_SYMBOL(gsi_dealloc_channel);
@@ -2751,6 +2764,7 @@ EXPORT_SYMBOL(gsi_poll_channel);
int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
{
	struct gsi_chan_ctx *ctx;
	struct gsi_chan_ctx *shared_ch_ctx;
	enum gsi_chan_mode curr;
	unsigned long flags;

@@ -2793,13 +2807,39 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
			mode == GSI_CHAN_MODE_POLL) {
		__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
		atomic_set(&ctx->poll_mode, mode);
		if ((ctx->props.common_evt_ring) &&
			(gsi_ctx->shared_ch_info.ch_id == chan_hdl)) {
			atomic_set(&ctx->evtr->chan->poll_mode, mode);
		} else if ((ctx->props.common_evt_ring) &&
				gsi_ctx->shared_ch_info.evchid ==
					ctx->evtr->id) {
			shared_ch_ctx =
				&gsi_ctx->chan[gsi_ctx->shared_ch_info.ch_id];
			if (shared_ch_ctx != NULL)
				atomic_set(&shared_ch_ctx->poll_mode, mode);
		}
		GSIDBG("set gsi_ctx evtr_id %d to %d mode\n",
			ctx->evtr->id, mode);
		ctx->stats.callback_to_poll++;
	}

	if (curr == GSI_CHAN_MODE_POLL &&
			mode == GSI_CHAN_MODE_CALLBACK) {
		atomic_set(&ctx->poll_mode, mode);
		if ((ctx->props.common_evt_ring) &&
			(gsi_ctx->shared_ch_info.ch_id == chan_hdl)) {
			atomic_set(&ctx->evtr->chan->poll_mode, mode);
		} else if ((ctx->props.common_evt_ring) &&
				gsi_ctx->shared_ch_info.evchid ==
				ctx->evtr->id) {
			shared_ch_ctx =
				&gsi_ctx->chan[gsi_ctx->shared_ch_info.ch_id];
			if (shared_ch_ctx != NULL)
				atomic_set(&shared_ch_ctx->poll_mode, mode);
		}
		__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
		GSIDBG("set gsi_ctx evtr_id %d to %d mode\n",
			ctx->evtr->id, mode);
		ctx->stats.poll_to_callback++;
	}
	spin_unlock_irqrestore(&gsi_ctx->slock, flags);
+8 −1
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -190,6 +190,11 @@ struct gsi_generic_ee_cmd_debug_stats {
	unsigned long halt_channel;
};

struct gsi_shared_chan_info {
	uint8_t ch_id;
	uint8_t evchid;
};

struct gsi_ctx {
	void __iomem *base;
	struct device *dev;
@@ -213,6 +218,8 @@ struct gsi_ctx {
	struct completion gen_ee_cmd_compl;
	void *ipc_logbuf;
	void *ipc_logbuf_low;
	struct gsi_shared_chan_info shared_ch_info;

	/*
	 * The following used only on emulation systems.
	 */
+96 −16
Original line number Diff line number Diff line
/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -102,11 +102,14 @@ static int ipa_populate_tag_field(struct ipa3_desc *desc,
		struct ipa3_tx_pkt_wrapper *tx_pkt,
		struct ipahal_imm_cmd_pyld **tag_pyld_ret);
static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
	struct ipa_mem_buffer *mem_info);
	struct ipa_mem_buffer *mem_info,
	struct gsi_chan_xfer_notify *xfer_notify);
static unsigned long tag_to_pointer_wa(uint64_t tag);
static uint64_t pointer_to_tag_wa(struct ipa3_tx_pkt_wrapper *tx_pkt);

static u32 ipa_adjust_ra_buff_base_sz(u32 aggr_byte_limit);
static bool ipa_update_common_evt_ring(enum ipa_client_type src,
	enum ipa_client_type dst);

static void ipa3_wq_write_done_common(struct ipa3_sys_context *sys,
				struct ipa3_tx_pkt_wrapper *tx_pkt)
@@ -710,20 +713,24 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
	int ret;
	int cnt = 0;
	struct ipa_mem_buffer mem_info = { 0 };
	struct gsi_chan_xfer_notify notify;

	memset(&notify, 0, sizeof(struct gsi_chan_xfer_notify));
	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
		!atomic_read(&sys->curr_polling_state))) {
		if (cnt && !process_all)
			break;

		ret = ipa_poll_gsi_pkt(sys, &mem_info);
		ret = ipa_poll_gsi_pkt(sys, &mem_info, &notify);
		if (ret)
			break;

		if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(sys->ep->client))
			ipa3_dma_memcpy_notify(sys, &mem_info);
		else if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client))
			ipa3_wlan_wq_rx_common(sys, mem_info.size);
			ipa3_wlan_wq_rx_common(
			(struct ipa3_sys_context *)(notify.chan_user_data),
			mem_info.size);
		else
			ipa3_wq_rx_common(sys, mem_info.size);

@@ -738,6 +745,8 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all,
static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
{
	int ret;
	u32 wlan_ep_idx;
	struct ipa3_ep_context *wlan_ep;

	if (!atomic_read(&sys->curr_polling_state)) {
		IPAERR("already in intr mode\n");
@@ -751,6 +760,16 @@ static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys)
		IPAERR("Failed to switch to intr mode.\n");
		goto fail;
	}
	if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client)) {
		wlan_ep_idx = ipa3_get_ep_mapping(
			((sys->ep->client == IPA_CLIENT_WLAN2_CONS) ?
			IPA_CLIENT_WLAN3_CONS : IPA_CLIENT_WLAN2_CONS));
		if (wlan_ep_idx != IPA_EP_NOT_ALLOCATED &&
			ipa3_ctx->ep[wlan_ep_idx].valid == 1) {
			wlan_ep = &ipa3_ctx->ep[wlan_ep_idx];
			atomic_set(&wlan_ep->sys->curr_polling_state, 0);
		}
	}
	return;

fail:
@@ -1182,6 +1201,12 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
		ipa3_ctx->gsi_evt_comm_ring_rem +=
			ep->gsi_mem_info.chan_ring_len;
	} else if (ep->gsi_evt_ring_hdl != ~0) {
		/* common event ring is used for WLAN2/WLAN3 pipes */
		if (IPA_IS_4_0_AUTO_CONFIG() &&
			ep->client == IPA_CLIENT_WLAN2_CONS) {
			/* Skip resetting the channel. */
			goto teardown;
		}
		result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
		if (result != GSI_STATUS_SUCCESS) {
			IPAERR("Failed to reset evt ring: %d.\n",
@@ -1201,6 +1226,8 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
			return result;
		}
	}

teardown:
	if (ep->sys->repl_wq)
		flush_workqueue(ep->sys->repl_wq);
	if (IPA_CLIENT_IS_CONS(ep->client))
@@ -3412,8 +3439,21 @@ static void ipa_gsi_irq_tx_notify_cb(struct gsi_chan_xfer_notify *notify)
void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
{
	bool clk_off;
	u32 wlan_ep_idx;
	struct ipa3_ep_context *wlan_ep;

	atomic_set(&sys->curr_polling_state, 1);
	if (IPA_CLIENT_IS_WLAN_CONS(sys->ep->client)) {
		wlan_ep_idx = ipa3_get_ep_mapping(
			((sys->ep->client == IPA_CLIENT_WLAN2_CONS) ?
			IPA_CLIENT_WLAN3_CONS : IPA_CLIENT_WLAN2_CONS));
		if (wlan_ep_idx != IPA_EP_NOT_ALLOCATED &&
			ipa3_ctx->ep[wlan_ep_idx].valid == 1) {
			wlan_ep = &ipa3_ctx->ep[wlan_ep_idx];
			/* Set the polling state. */
			atomic_set(&wlan_ep->sys->curr_polling_state, 1);
		}
	}
	ipa3_inc_acquire_wakelock();

	/*
@@ -3463,11 +3503,7 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
					   struct ipa3_rx_pkt_wrapper, link);
	rx_pkt_rcvd = (struct ipa3_rx_pkt_wrapper *)notify->xfer_user_data;

	if (rx_pkt_expected != rx_pkt_rcvd) {
		IPAERR("Pkt was not filled in head of rx buffer.\n");
		WARN_ON(1);
		return;
	}
	sys->ep->xfer_notify = *notify;
	sys->ep->bytes_xfered_valid = true;
	sys->ep->bytes_xfered = notify->bytes_xfered;
	sys->ep->phys_base = rx_pkt_rcvd->data.dma_addr;
@@ -3534,6 +3570,26 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
	}
}

static bool ipa_update_common_evt_ring(enum ipa_client_type src,
	enum ipa_client_type dst)
{
	u32 src_ep_idx, dst_ep_idx;

	src_ep_idx = ipa3_get_ep_mapping(src);
	dst_ep_idx = ipa3_get_ep_mapping(dst);
	if (src_ep_idx != IPA_EP_NOT_ALLOCATED &&
		ipa3_ctx->ep[src_ep_idx].valid == 1 &&
		dst_ep_idx != IPA_EP_NOT_ALLOCATED &&
		ipa3_ctx->ep[dst_ep_idx].valid == 1) {
		/* copy event ring handle */
		ipa3_ctx->ep[dst_ep_idx].gsi_evt_ring_hdl =
			ipa3_ctx->ep[src_ep_idx].gsi_evt_ring_hdl;
		return true;
	}
	return false;
}


int ipa3_alloc_common_event_ring(void)
{
	struct gsi_evt_ring_props gsi_evt_ring_props;
@@ -3611,6 +3667,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
		ep->gsi_evt_ring_hdl = ipa3_ctx->gsi_evt_comm_hdl;
	} else if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
	     IPA_CLIENT_IS_CONS(ep->client)) {
		/* Use common event ring in auto config for WLAN2/WLAN3 pipes */
		if (IPA_IS_4_0_AUTO_CONFIG() &&
			(ep->client == IPA_CLIENT_WLAN3_CONS) &&
			ipa_update_common_evt_ring(IPA_CLIENT_WLAN2_CONS,
				ep->client)) {
			goto setup_channel;
		}
		gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
		gsi_evt_ring_props.intr = GSI_INTR_IRQ;
		gsi_evt_ring_props.re_size =
@@ -3623,6 +3686,14 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
		 */
		gsi_evt_ring_props.ring_len = 2 * in->desc_fifo_sz;

		/* In Auto config, common event ring is used for WLAN sys pipes.
		 * Double the event ring size.
		 */
		if (IPA_IS_4_0_AUTO_CONFIG() &&
		    IPA_CLIENT_IS_WLAN_CONS(ep->client))
			gsi_evt_ring_props.ring_len =
				2 * gsi_evt_ring_props.ring_len;

		gsi_evt_ring_props.ring_base_vaddr =
			dma_alloc_coherent(ipa3_ctx->pdev,
			gsi_evt_ring_props.ring_len,
@@ -3659,6 +3730,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
			goto fail_alloc_evt_ring;
	}

setup_channel:
	memset(&gsi_channel_props, 0, sizeof(gsi_channel_props));
	gsi_channel_props.prot = GSI_CHAN_PROT_GPI;
	if (IPA_CLIENT_IS_PROD(ep->client)) {
@@ -3731,6 +3803,12 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
		gsi_channel_props.xfer_cb = ipa_gsi_irq_rx_notify_cb;
	if (IPA_CLIENT_IS_MEMCPY_DMA_CONS(ep->client))
		gsi_channel_props.xfer_cb = ipa_dma_gsi_irq_rx_notify_cb;

	/* In Auto config, common event ring is used for WLAN sys pipes.*/
	if (IPA_IS_4_0_AUTO_CONFIG() &&
	    IPA_CLIENT_IS_WLAN_CONS(ep->client))
		gsi_channel_props.common_evt_ring = true;

	result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl,
		&ep->gsi_chan_hdl);
	if (result != GSI_STATUS_SUCCESS)
@@ -3814,21 +3892,22 @@ static int ipa_populate_tag_field(struct ipa3_desc *desc,
}

static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
		struct ipa_mem_buffer *mem_info)
		struct ipa_mem_buffer *mem_info,
		struct gsi_chan_xfer_notify *xfer_notify)
{
	int ret;
	struct gsi_chan_xfer_notify xfer_notify;
	struct ipa3_rx_pkt_wrapper *rx_pkt;

	if (sys->ep->bytes_xfered_valid) {
		mem_info->phys_base = sys->ep->phys_base;
		mem_info->size = (u32)sys->ep->bytes_xfered;
		sys->ep->bytes_xfered_valid = false;
		*xfer_notify = sys->ep->xfer_notify;
		return GSI_STATUS_SUCCESS;
	}

	ret = gsi_poll_channel(sys->ep->gsi_chan_hdl,
		&xfer_notify);
		xfer_notify);
	if (ret == GSI_STATUS_POLL_EMPTY)
		return ret;
	else if (ret != GSI_STATUS_SUCCESS) {
@@ -3837,9 +3916,9 @@ static int ipa_poll_gsi_pkt(struct ipa3_sys_context *sys,
	}

	rx_pkt = (struct ipa3_rx_pkt_wrapper *)
		xfer_notify.xfer_user_data;
		(xfer_notify->xfer_user_data);
	mem_info->phys_base = rx_pkt->data.dma_addr;
	mem_info->size = xfer_notify.bytes_xfered;
	mem_info->size = xfer_notify->bytes_xfered;

	return ret;
}
@@ -3861,6 +3940,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
	struct ipa_mem_buffer mem_info = {0};
	static int total_cnt;
	struct ipa_active_client_logging_info log;
	struct gsi_chan_xfer_notify notify;

	IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");

@@ -3869,14 +3949,14 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight)
		IPAERR("bad parm 0x%x\n", clnt_hdl);
		return cnt;
	}

	memset(&notify, 0, sizeof(struct gsi_chan_xfer_notify));
	ep = &ipa3_ctx->ep[clnt_hdl];

	while (cnt < weight &&
		   atomic_read(&ep->sys->curr_polling_state)) {

		atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
		ret = ipa_poll_gsi_pkt(ep->sys, &mem_info);
		ret = ipa_poll_gsi_pkt(ep->sys, &mem_info, &notify);
		if (ret)
			break;

+7 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -385,6 +385,10 @@
#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311
#define TZ_MEM_PROTECT_REGION_ID 0x10

#define IPA_IS_4_0_AUTO_CONFIG() \
	((ipa3_ctx->ipa_hw_type == IPA_HW_v4_0) && \
	(ipa3_ctx->ipa_config_is_auto))

struct ipa3_active_client_htable_entry {
	struct hlist_node list;
	char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
@@ -728,6 +732,7 @@ struct ipa3_status_stats {
 * @gsi_evt_ring_hdl: EP's GSI channel event ring handle
 * @gsi_mem_info: EP's GSI channel rings info
 * @chan_scratch: EP's GSI channel scratch info
 * @xfer_notify: transfer element
 * @cfg: EP cionfiguration
 * @dst_pipe_index: destination pipe index
 * @rt_tbl_idx: routing table index
@@ -752,6 +757,7 @@ struct ipa3_ep_context {
	unsigned long gsi_evt_ring_hdl;
	struct ipa_gsi_ep_mem_info gsi_mem_info;
	union __packed gsi_channel_scratch chan_scratch;
	struct gsi_chan_xfer_notify xfer_notify;
	bool bytes_xfered_valid;
	u16 bytes_xfered;
	dma_addr_t phys_base;
+3 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -352,7 +352,7 @@ enum gsi_chan_use_db_eng {
 *
 * @err_cb:          error notification callback
 * @chan_user_data:  cookie used for notifications
 *
 * @common_evt_ring: Boolean indicating common event ring.
 * All the callbacks are in interrupt context
 *
 */
@@ -373,6 +373,7 @@ struct gsi_chan_props {
	void (*xfer_cb)(struct gsi_chan_xfer_notify *notify);
	void (*err_cb)(struct gsi_chan_err_notify *notify);
	void *chan_user_data;
	bool common_evt_ring;
};

enum gsi_xfer_flag {