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

Commit 8568eb9e authored by Skylar Chang's avatar Skylar Chang
Browse files

msm: gsi: reduce register accesses on data path



Optimize the way GSI driver reads writes registers in the data path.
RP (read pointer) will get read only in case the cached value cannot
be used. For event ring for FROM_GSI, the WP (write pointer, doorbell),
will be advanced based on channel credits.

Change-Id: I73267f9011c9568083e94fc5c398750318626ba5
CRs-Fixed: 2022853
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent d738ee3f
Loading
Loading
Loading
Loading
+43 −30
Original line number Diff line number Diff line
@@ -415,6 +415,16 @@ static void gsi_ring_chan_doorbell(struct gsi_chan_ctx *ctx)
{
	uint32_t val;

	/*
	 * allocate new events for this channel first
	 * before submitting the new TREs.
	 * for TO_GSI channels the event ring doorbell is rang as part of
	 * interrupt handling.
	 */
	if (ctx->evtr && ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
		gsi_ring_evt_doorbell(ctx->evtr);
	ctx->ring.wp = ctx->ring.wp_local;

	/* write order MUST be MSB followed by LSB */
	val = ((ctx->ring.wp_local >> 32) &
			GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK) <<
@@ -470,8 +480,8 @@ static void gsi_handle_ieob(int ee)
			cntr = 0;
			rp = gsi_readl(gsi_ctx->base +
				GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(i, ee));
			rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
				GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(i, ee))) << 32;
			rp |= ctx->ring.rp & 0xFFFFFFFF00000000;

			ctx->ring.rp = rp;
			while (ctx->ring.rp_local != rp) {
				++cntr;
@@ -1529,6 +1539,7 @@ static void gsi_init_chan_ring(struct gsi_chan_props *props,
static int gsi_validate_channel_props(struct gsi_chan_props *props)
{
	uint64_t ra;
	uint64_t last;

	if (props->ch_id >= gsi_ctx->max_ch) {
		GSIERR("ch_id %u invalid\n", props->ch_id);
@@ -1556,6 +1567,17 @@ static int gsi_validate_channel_props(struct gsi_chan_props *props)
		return -GSI_STATUS_INVALID_PARAMS;
	}

	last = props->ring_base_addr + props->ring_len - props->re_size;

	/* MSB should stay same within the ring */
	if ((props->ring_base_addr & 0xFFFFFFFF00000000ULL) !=
	    (last & 0xFFFFFFFF00000000ULL)) {
		GSIERR("MSB is not fixed on ring base 0x%llx size 0x%x\n",
			props->ring_base_addr,
			props->ring_len);
		return -GSI_STATUS_INVALID_PARAMS;
	}

	if (props->prot == GSI_CHAN_PROT_GPI &&
			!props->ring_base_vaddr) {
		GSIERR("protocol %u requires ring base VA\n", props->prot);
@@ -2128,29 +2150,22 @@ static void __gsi_query_channel_free_re(struct gsi_chan_ctx *ctx,
		uint16_t *num_free_re)
{
	uint16_t start;
	uint16_t start_hw;
	uint16_t end;
	uint64_t rp;
	uint64_t rp_hw;
	int ee = gsi_ctx->per.ee;
	uint16_t used;
	uint16_t used_hw;

	rp_hw = gsi_readl(gsi_ctx->base +
	if (!ctx->evtr) {
		rp = gsi_readl(gsi_ctx->base +
			GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
	rp_hw |= ((uint64_t)gsi_readl(gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee)))
		<< 32;
		rp |= ctx->ring.rp & 0xFFFFFFFF00000000;

	if (!ctx->evtr) {
		rp = rp_hw;
		ctx->ring.rp = rp;
	} else {
		rp = ctx->ring.rp_local;
	}

	start = gsi_find_idx_from_addr(&ctx->ring, rp);
	start_hw = gsi_find_idx_from_addr(&ctx->ring, rp_hw);
	end = gsi_find_idx_from_addr(&ctx->ring, ctx->ring.wp_local);

	if (end >= start)
@@ -2158,13 +2173,7 @@ static void __gsi_query_channel_free_re(struct gsi_chan_ctx *ctx,
	else
		used = ctx->ring.max_num_elem + 1 - (start - end);

	if (end >= start_hw)
		used_hw = end - start_hw;
	else
		used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end);

	*num_free_re = ctx->ring.max_num_elem - used;
	gsi_update_ch_dp_stats(ctx, used_hw);
}

int gsi_query_channel_info(unsigned long chan_hdl,
@@ -2274,14 +2283,12 @@ int gsi_is_channel_empty(unsigned long chan_hdl, bool *is_empty)

	rp = gsi_readl(gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
	rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee))) << 32;
	rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
	ctx->ring.rp = rp;

	wp = gsi_readl(gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(ctx->props.ch_id, ee));
	wp |= ((uint64_t)gsi_readl(gsi_ctx->base +
		GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(ctx->props.ch_id, ee))) << 32;
	wp |= ctx->ring.wp & 0xFFFFFFFF00000000;
	ctx->ring.wp = wp;

	if (ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
@@ -2420,6 +2427,9 @@ int gsi_start_xfer(unsigned long chan_hdl)
		return -GSI_STATUS_UNSUPPORTED_OP;
	}

	if (ctx->ring.wp == ctx->ring.wp_local)
		return GSI_STATUS_SUCCESS;

	gsi_ring_chan_doorbell(ctx);

	return GSI_STATUS_SUCCESS;
@@ -2457,19 +2467,22 @@ int gsi_poll_channel(unsigned long chan_hdl,
	}

	spin_lock_irqsave(&ctx->evtr->ring.slock, flags);
	if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
		/* update rp to see of we have anything new to process */
		rp = gsi_readl(gsi_ctx->base +
			GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(ctx->evtr->id, ee));
	rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
		GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(ctx->evtr->id, ee))) << 32;
		rp |= ctx->ring.rp & 0xFFFFFFFF00000000;

		ctx->evtr->ring.rp = rp;
	if (rp == ctx->evtr->ring.rp_local) {
	}

	if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
		spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
		ctx->stats.poll_empty++;
		return GSI_STATUS_POLL_EMPTY;
	}

	gsi_process_evt_re(ctx->evtr, notify, false);
	gsi_ring_evt_doorbell(ctx->evtr);
	spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
	ctx->stats.poll_ok++;

+1 −7
Original line number Diff line number Diff line
@@ -490,11 +490,6 @@ static ssize_t gsi_enable_dp_stats(struct file *file,
		goto error;
	}

	if (gsi_ctx->chan[ch_id].props.prot == GSI_CHAN_PROT_GPI) {
		TERR("valid for non GPI channels only\n");
		goto error;
	}

	if (gsi_ctx->chan[ch_id].enable_dp_stats == enable) {
		TERR("ch_%d: already enabled/disabled\n", ch_id);
		return -EFAULT;
@@ -631,7 +626,7 @@ static void gsi_dbg_update_ch_dp_stats(struct gsi_chan_ctx *ctx)
	else
		used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end_hw);

	TERR("ch %d used %d\n", ctx->props.ch_id, used_hw);
	TDBG("ch %d used %d\n", ctx->props.ch_id, used_hw);
	gsi_update_ch_dp_stats(ctx, used_hw);
}

@@ -641,7 +636,6 @@ static void gsi_wq_update_dp_stats(struct work_struct *work)

	for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
		if (gsi_ctx->chan[ch_id].allocated &&
		    gsi_ctx->chan[ch_id].props.prot != GSI_CHAN_PROT_GPI &&
		    gsi_ctx->chan[ch_id].enable_dp_stats)
			gsi_dbg_update_ch_dp_stats(&gsi_ctx->chan[ch_id]);
	}