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

Commit bd1496b6 authored by Liron Kuch's avatar Liron Kuch
Browse files

msm: tspp2: Fix handling of context-based counters



TSPP2 HW maintains various statistics counters. These HW counters are
based on the context index rather than the filter HW index. Fix the driver
to use the appropriate index when dispaying the counters in debugfs and
when resetting the counters.

Change-Id: I2098bf5fd936ca9f1a136b925da2f7998b8c0c96
Signed-off-by: default avatarLiron Kuch <lkuch@codeaurora.org>
parent 02983880
Loading
Loading
Loading
Loading
+119 −72
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ enum tspp2_operation_opcode {
/* Bits for TSPP2_FILTER_ENTRY1 register */
#define FILTER_ENTRY1_CONTEXT_OFFS	0

/* Filter counter register definitions: n = 0..127 */
/* Filter context-based counter register definitions: n = 0..127 */
#define TSPP2_FILTER_TSP_SYNC_ERROR(n)		(0x4000 + ((n) << 2))
#define TSPP2_FILTER_ERRED_TSP(n)		(0x4200 + ((n) << 2))
#define TSPP2_FILTER_DISCONTINUITIES(n)		(0x4400 + ((n) << 2))
@@ -733,12 +733,12 @@ struct tspp2_pipe_irq_stats {
};

/**
 * struct tspp2_filter_irq_stats - Filter interrupt statistics counters
 * struct tspp2_filter_context_irq_stats - Filter interrupt statistics counters
 *
 * @sc_go_high:	Scrambling bits change from clear to encrypted.
 * @sc_go_low:	Scrambling bits change from encrypted to clear.
 */
struct tspp2_filter_irq_stats {
struct tspp2_filter_context_irq_stats {
	u32 sc_go_high;
	u32 sc_go_low;
};
@@ -750,14 +750,14 @@ struct tspp2_filter_irq_stats {
 * @src:	Memory source interrupt statistics counters
 * @kt:		Key table interrupt statistics counters
 * @pipe:	Pipe interrupt statistics counters
 * @filter:	Filter interrupt statistics counters
 * @ctx:	Filter context interrupt statistics counters
 */
struct tspp2_irq_stats {
	struct tspp2_global_irq_stats global;
	struct tspp2_src_irq_stats src[TSPP2_NUM_MEM_INPUTS];
	struct tspp2_keytable_irq_stats kt[TSPP2_NUM_KEYTABLES];
	struct tspp2_pipe_irq_stats pipe[TSPP2_NUM_PIPES];
	struct tspp2_filter_irq_stats filter[TSPP2_NUM_HW_FILTERS];
	struct tspp2_filter_context_irq_stats ctx[TSPP2_NUM_CONTEXTS];
};

/**
@@ -1226,6 +1226,45 @@ static int filter_debugfs_print(struct seq_file *s, void *p)
	seq_printf(s, "raw_op_set: %d\n", filter->raw_op_set);
	seq_printf(s, "pes_tx_op_set: %d\n", filter->pes_tx_op_set);
	seq_printf(s, "Status: %s\n", filter->enabled ? "enabled" : "disabled");

	if (filter->enabled) {
		seq_printf(s, "Filter context-based counters, context %d\n",
				filter->context);
		seq_printf(s, "filter_tsp_sync_err = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_TSP_SYNC_ERROR(filter->context)));
		seq_printf(s, "filter_erred_tsp = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_ERRED_TSP(filter->context)));
		seq_printf(s, "filter_discontinuities = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_DISCONTINUITIES(filter->context)));
		seq_printf(s, "filter_sc_bits_discard = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(filter->context)));
		seq_printf(s, "filter_tsp_total_num = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_TSP_TOTAL_NUM(filter->context)));
		seq_printf(s, "filter_discont_indicator = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_DISCONT_INDICATOR(filter->context)));
		seq_printf(s, "filter_tsp_no_payload = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_TSP_NO_PAYLOAD(filter->context)));
		seq_printf(s, "filter_tsp_duplicate = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_TSP_DUPLICATE(filter->context)));
		seq_printf(s, "filter_key_fetch_fail = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_KEY_FETCH_FAILURE(filter->context)));
		seq_printf(s, "filter_dropped_pcr = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_DROPPED_PCR(filter->context)));
		seq_printf(s, "filter_pes_errors = 0x%08X\n",
			readl_relaxed(filter->device->base +
			TSPP2_FILTER_PES_ERRORS(filter->context)));
	}

	return 0;
}

@@ -1369,35 +1408,11 @@ static void tspp2_debugfs_init(struct tspp2_device *device)
			&device->irq_stats.global.encrypt_level_err);
	}

	dir = debugfs_create_dir("filters", device->debugfs_entry);
	for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) {
		snprintf(name, 80, "filter%03i", i);
	dir = debugfs_create_dir("counters", device->debugfs_entry);
	for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) {
		snprintf(name, 80, "context%03i", i);
		dentry = debugfs_create_dir(name, dir);
		if (dentry) {
			debugfs_create_u32(
				"stat_sc_go_high",
				S_IRUGO | S_IWUSR | S_IWGRP,
				dentry,
				&device->irq_stats.filter[i].sc_go_high);

			debugfs_create_u32(
				"stat_sc_go_low",
				S_IRUGO | S_IWUSR | S_IWGRP,
				dentry,
				&device->irq_stats.filter[i].sc_go_low);

			debugfs_create_file("filter_entry0",
				TSPP2_S_RW,
				dentry,
				base + TSPP2_FILTER_ENTRY0(i),
				&fops_iomem_x32);

			debugfs_create_file("filter_entry1",
				TSPP2_S_RW,
				dentry,
				base + TSPP2_FILTER_ENTRY1(i),
				&fops_iomem_x32);

			debugfs_create_file("filter_tsp_sync_err",
				TSPP2_S_RW,
				dentry,
@@ -1464,6 +1479,37 @@ static void tspp2_debugfs_init(struct tspp2_device *device)
				base + TSPP2_FILTER_PES_ERRORS(i),
				&fops_iomem_x32);

			debugfs_create_u32(
				"stat_sc_go_high",
				S_IRUGO | S_IWUSR | S_IWGRP,
				dentry,
				&device->irq_stats.ctx[i].sc_go_high);

			debugfs_create_u32(
				"stat_sc_go_low",
				S_IRUGO | S_IWUSR | S_IWGRP,
				dentry,
				&device->irq_stats.ctx[i].sc_go_low);
		}
	}

	dir = debugfs_create_dir("filters", device->debugfs_entry);
	for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) {
		snprintf(name, 80, "filter%03i", i);
		dentry = debugfs_create_dir(name, dir);
		if (dentry) {
			debugfs_create_file("filter_entry0",
				TSPP2_S_RW,
				dentry,
				base + TSPP2_FILTER_ENTRY0(i),
				&fops_iomem_x32);

			debugfs_create_file("filter_entry1",
				TSPP2_S_RW,
				dentry,
				base + TSPP2_FILTER_ENTRY1(i),
				&fops_iomem_x32);

			for (j = 0; j < TSPP2_MAX_OPS_PER_FILTER; j++) {
				snprintf(name, 80, "opcode%02i", j);
				debugfs_create_file(name,
@@ -1948,27 +1994,24 @@ static void tspp2_clock_stop(struct tspp2_device *device)
 * tspp2_filter_counters_reset() - Reset a filter's HW counters.
 *
 * @device:	TSPP2 device.
 * @hw_index:	Filter HW index.
 * @index:	Filter context index. Note counters are based on the context
 *		index and not on the filter HW index.
 */
static void tspp2_filter_counters_reset(struct tspp2_device *device,
					u32 hw_index)
static void tspp2_filter_counters_reset(struct tspp2_device *device, u32 index)
{
	/* Reset filter counters */
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(hw_index));
	writel_relaxed(0,
		device->base + TSPP2_FILTER_DISCONTINUITIES(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_DISCONTINUITIES(index));
	writel_relaxed(0,
		device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(hw_index));
	writel_relaxed(0,
		device->base + TSPP2_FILTER_DISCONT_INDICATOR(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(hw_index));
	writel_relaxed(0,
		device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(hw_index));
	writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(hw_index));
		device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_DISCONT_INDICATOR(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(index));
	writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(index));
}

/**
@@ -2075,7 +2118,10 @@ static int tspp2_global_hw_reset(struct tspp2_device *device,
		/* Disable all HW filters */
		writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY0(i));
		writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY1(i));
		/* Reset filter counters */
	}

	for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) {
		/* Reset filter context-based counters */
		tspp2_filter_counters_reset(device, i);
	}

@@ -5062,8 +5108,8 @@ int tspp2_src_filters_clear(u32 src_handle)
			TSPP2_FILTER_ENTRY0(filter->hw_index));
		/* Clear filter operations in HW as well as related SW fields */
		tspp2_filter_ops_clear(filter);
		/* Reset filter counters */
		tspp2_filter_counters_reset(filter->device, filter->hw_index);
		/* Reset filter context-based counters */
		tspp2_filter_counters_reset(filter->device, filter->context);
		/* Reset filter context and release it back to the device */
		tspp2_filter_context_reset(filter);
		/* Reset filter SW fields */
@@ -5229,6 +5275,7 @@ int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle)
		if (i == TSPP2_NUM_BATCHES) {
			pr_err("%s: No available filters\n", __func__);
			src->device->contexts[filter->context] = 0;
			filter->context = 0;
			mutex_unlock(&src->device->mutex);
			pm_runtime_mark_last_busy(src->device->dev);
			pm_runtime_put_autosuspend(src->device->dev);
@@ -5265,8 +5312,8 @@ int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle)
	list_add_tail(&filter->link, &src->filters_list);
	src->num_associated_filters++;

	/* Reset filter counters */
	tspp2_filter_counters_reset(filter->device, filter->hw_index);
	/* Reset filter context-based counters */
	tspp2_filter_counters_reset(filter->device, filter->context);

	/* Reset this filter's context */
	writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
@@ -5378,8 +5425,8 @@ int tspp2_filter_close(u32 filter_handle)
	/* Clear filter operations in HW as well as related SW fields */
	tspp2_filter_ops_clear(filter);

	/* Reset filter counters */
	tspp2_filter_counters_reset(device, filter->hw_index);
	/* Reset filter context-based counters */
	tspp2_filter_counters_reset(device, filter->context);

	/* Reset filter context and release it back to the device */
	tspp2_filter_context_reset(filter);
@@ -6315,9 +6362,6 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter,
		return -EINVAL;
	}

	/* Reset new filter HW counters */
	tspp2_filter_counters_reset(filter->device, tmp_filter->hw_index);

	/* Set the same context of the old filter to the new HW filter */
	writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS),
		filter->device->base +
@@ -6329,6 +6373,10 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter,
	 * that uses a context where before there was no operation that used it,
	 * we reset that context. We need to do this before we start using the
	 * new operation, so before we enable the new filter.
	 * Note: there is no need to reset most of the filter's context-based
	 * counters, because the filter keeps using the same context. The
	 * exception is the PES error counters that we may want to reset when
	 * resetting the entire PES context.
	 */
	if (!filter->pes_tx_op_set && tmp_filter->pes_tx_op_set) {
		/* PES Tx operation added */
@@ -6336,6 +6384,8 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter,
			(0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
			filter->device->base +
			TSPP2_PES_CONTEXT_RESET(filter->context >> 5));
		writel_relaxed(0, filter->device->base +
			TSPP2_FILTER_PES_ERRORS(filter->context));
	}

	if (!filter->indexing_op_set && tmp_filter->indexing_op_set) {
@@ -6379,9 +6429,6 @@ static int tspp2_filter_ops_update(struct tspp2_filter *filter,
	/* The new HW filter may be in a new batch, so we need to update */
	filter->batch = batch;

	/* Reset old filter HW counters */
	tspp2_filter_counters_reset(filter->device, filter->hw_index);

	/*
	 * Update source's reserved filter HW index, and also update the
	 * new HW index in the filter object.
@@ -7318,14 +7365,14 @@ int tspp2_filter_event_notification_register(u32 filter_handle,
	spin_unlock_irqrestore(&filter->device->spinlock, flags);

	/* Enable/disable SC high/low interrupts per filter as requested */
	idx = (filter->hw_index >> 5);
	idx = (filter->context >> 5);
	reg = readl_relaxed(filter->device->base +
		TSPP2_SC_GO_HIGH_ENABLE(idx));
	if (callback &&
		(filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_HIGH)) {
		reg |= (0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32));
		reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32));
	} else {
		reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32));
		reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32));
	}
	writel_relaxed(reg, filter->device->base +
		TSPP2_SC_GO_HIGH_ENABLE(idx));
@@ -7334,9 +7381,9 @@ int tspp2_filter_event_notification_register(u32 filter_handle,
		TSPP2_SC_GO_LOW_ENABLE(idx));
	if (callback &&
		(filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_LOW)) {
		reg |= (0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32));
		reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32));
	} else {
		reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->hw_index, 32));
		reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32));
	}
	writel_relaxed(reg, filter->device->base +
		TSPP2_SC_GO_LOW_ENABLE(idx));
@@ -7926,7 +7973,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev)
	u32 i = 0, j = 0;
	u32 global_bitmask = 0;
	u32 src_bitmask[TSPP2_NUM_MEM_INPUTS] = {0};
	u32 filter_bitmask[TSPP2_NUM_HW_FILTERS] = {0};
	u32 filter_bitmask[TSPP2_NUM_CONTEXTS] = {0};
	u32 reg = 0;

	reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_STATUS);
@@ -7993,7 +8040,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev)
			for_each_set_bit(i, &ext_reg, 32) {
				filter_bitmask[j*32 + i] |=
					TSPP2_FILTER_EVENT_SCRAMBLING_HIGH;
				device->irq_stats.filter[j*32 + i].sc_go_high++;
				device->irq_stats.ctx[j*32 + i].sc_go_high++;
			}
			writel_relaxed(ext_reg, device->base +
					TSPP2_SC_GO_HIGH_CLEAR(j));
@@ -8007,7 +8054,7 @@ static irqreturn_t tspp2_isr(int irq, void *dev)
			for_each_set_bit(i, &ext_reg, 32) {
				filter_bitmask[j*32 + i] |=
					TSPP2_FILTER_EVENT_SCRAMBLING_LOW;
				device->irq_stats.filter[j*32 + i].sc_go_low++;
				device->irq_stats.ctx[j*32 + i].sc_go_low++;
			}
			writel_relaxed(ext_reg, device->base +
					TSPP2_SC_GO_LOW_CLEAR(j));
@@ -8056,12 +8103,12 @@ static irqreturn_t tspp2_isr(int irq, void *dev)
	for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) {
		f = &device->filters[i];
		if (f->event_callback &&
			(f->event_bitmask & filter_bitmask[f->hw_index]))
			(f->event_bitmask & filter_bitmask[f->context]))
			tspp2_event_work_prepare(device,
				f->event_callback,
				f->event_cookie,
				(f->event_bitmask &
					filter_bitmask[f->hw_index]));
					filter_bitmask[f->context]));
	}

	spin_unlock_irqrestore(&device->spinlock, flags);