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

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

Merge "msm: tspp2: Fix handling of context-based counters"

parents 145b1a9d bd1496b6
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);