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

Commit 262e85b1 authored by Satyajit Desai's avatar Satyajit Desai
Browse files

coresight: stm: Remove spin lock usage for channel allocation



Current usage of spinlock in channel allocation might result in
live lock issue. In order to avoid this we move to a per cpu
channel allocation scheme. We rely on preemption being disabled
when we allocate channel to avoid any conflict. If we end up
handling an interrupt which logs when preemption is disabled it
is still gauranteed to not interfere with the current logging
as the channel id will be freed up before resuming.

Change-Id: I91d7fcb4ed9202328e62d5459283927e238f9f66
Signed-off-by: default avatarSatyajit Desai <sadesai@codeaurora.org>
parent 5915565f
Loading
Loading
Loading
Loading
+26 −15
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, 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
@@ -30,19 +30,26 @@

static struct stm_drvdata *stmdrvdata;

static uint32_t stm_channel_alloc(uint32_t off)
static uint32_t stm_channel_alloc(void)
{
	struct stm_drvdata *drvdata = stmdrvdata;
	uint32_t ch;
	unsigned long flags;
	uint32_t ch, off, num_ch_per_cpu;
	int cpu;

	num_ch_per_cpu = drvdata->numsp/num_present_cpus();

	spin_lock_irqsave(&drvdata->spinlock, flags);
	do {
	cpu = get_cpu();

	off = num_ch_per_cpu * cpu;
	ch = find_next_zero_bit(drvdata->chs.bitmap,
				drvdata->numsp, off);
	} while ((ch < drvdata->numsp) &&
		 test_and_set_bit(ch, drvdata->chs.bitmap));
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
	if (unlikely(ch >= (off + num_ch_per_cpu))) {
		put_cpu();
		return drvdata->numsp;
	}

	set_bit(ch, drvdata->chs.bitmap);
	put_cpu();

	return ch;
}
@@ -65,11 +72,8 @@ static int stm_ost_send(void *addr, const void *data, uint32_t count)
static void stm_channel_free(uint32_t ch)
{
	struct stm_drvdata *drvdata = stmdrvdata;
	unsigned long flags;

	spin_lock_irqsave(&drvdata->spinlock, flags);
	clear_bit(ch, drvdata->chs.bitmap);
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
}

static int stm_trace_ost_header(unsigned long ch_addr, uint32_t flags,
@@ -146,7 +150,14 @@ static inline int __stm_trace(uint32_t flags, uint8_t entity_id,
	unsigned long ch_addr;

	/* allocate channel and get the channel address */
	ch = stm_channel_alloc(0);
	ch = stm_channel_alloc();
	if (unlikely(ch >= drvdata->numsp)) {
		drvdata->ch_alloc_fail_count++;
		dev_err_ratelimited(drvdata->dev,
				    "Channel allocation failed %d",
				    drvdata->ch_alloc_fail_count);
		return 0;
	}

	ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);

+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 * Description: CoreSight System Trace Macrocell driver
 *
@@ -729,7 +729,7 @@ static u32 stm_num_stimulus_port(struct stm_drvdata *drvdata)
	numsp &= 0x1ffff;
	if (!numsp)
		numsp = STM_32_CHANNEL;
	return numsp;
	return STM_32_CHANNEL;
}

static void stm_init_default_data(struct stm_drvdata *drvdata)
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ struct channel_space {
 * @stmheer:		settings for register STMHEER.
 * @stmheter:		settings for register STMHETER.
 * @stmhebsr:		settings for register STMHEBSR.
 * @ch_alloc_fail_count:	Number of ch allocation failures over time.
 */
struct stm_drvdata {
	void __iomem		*base;
@@ -90,6 +91,7 @@ struct stm_drvdata {
	u32			stmheer;
	u32			stmheter;
	u32			stmhebsr;
	u32			ch_alloc_fail_count;
};

#ifdef CONFIG_CORESIGHT_STM