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

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

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

parents c335e606 02130724
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 {