162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2022 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "gt/intel_engine_regs.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "i915_drv.h"
962306a36Sopenharmony_ci#include "i915_gem.h"
1062306a36Sopenharmony_ci#include "i915_ioctl.h"
1162306a36Sopenharmony_ci#include "i915_reg.h"
1262306a36Sopenharmony_ci#include "intel_runtime_pm.h"
1362306a36Sopenharmony_ci#include "intel_uncore.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * This file is for small ioctl functions that are out of place everywhere else,
1762306a36Sopenharmony_ci * and not big enough to warrant a file of their own.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * This is not the dumping ground for random ioctls.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct reg_whitelist {
2362306a36Sopenharmony_ci	i915_reg_t offset_ldw;
2462306a36Sopenharmony_ci	i915_reg_t offset_udw;
2562306a36Sopenharmony_ci	u8 min_graphics_ver;
2662306a36Sopenharmony_ci	u8 max_graphics_ver;
2762306a36Sopenharmony_ci	u8 size;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const struct reg_whitelist reg_read_whitelist[] = {
3162306a36Sopenharmony_ci	{
3262306a36Sopenharmony_ci		.offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
3362306a36Sopenharmony_ci		.offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
3462306a36Sopenharmony_ci		.min_graphics_ver = 4,
3562306a36Sopenharmony_ci		.max_graphics_ver = 12,
3662306a36Sopenharmony_ci		.size = 8
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciint i915_reg_read_ioctl(struct drm_device *dev,
4162306a36Sopenharmony_ci			void *data, struct drm_file *unused)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct drm_i915_private *i915 = to_i915(dev);
4462306a36Sopenharmony_ci	struct intel_uncore *uncore = &i915->uncore;
4562306a36Sopenharmony_ci	struct drm_i915_reg_read *reg = data;
4662306a36Sopenharmony_ci	struct reg_whitelist const *entry;
4762306a36Sopenharmony_ci	intel_wakeref_t wakeref;
4862306a36Sopenharmony_ci	unsigned int flags;
4962306a36Sopenharmony_ci	int remain;
5062306a36Sopenharmony_ci	int ret = 0;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	entry = reg_read_whitelist;
5362306a36Sopenharmony_ci	remain = ARRAY_SIZE(reg_read_whitelist);
5462306a36Sopenharmony_ci	while (remain) {
5562306a36Sopenharmony_ci		u32 entry_offset = i915_mmio_reg_offset(entry->offset_ldw);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		GEM_BUG_ON(!is_power_of_2(entry->size));
5862306a36Sopenharmony_ci		GEM_BUG_ON(entry->size > 8);
5962306a36Sopenharmony_ci		GEM_BUG_ON(entry_offset & (entry->size - 1));
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (IS_GRAPHICS_VER(i915, entry->min_graphics_ver, entry->max_graphics_ver) &&
6262306a36Sopenharmony_ci		    entry_offset == (reg->offset & -entry->size))
6362306a36Sopenharmony_ci			break;
6462306a36Sopenharmony_ci		entry++;
6562306a36Sopenharmony_ci		remain--;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (!remain)
6962306a36Sopenharmony_ci		return -EINVAL;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	flags = reg->offset & (entry->size - 1);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
7462306a36Sopenharmony_ci		if (entry->size == 8 && flags == I915_REG_READ_8B_WA)
7562306a36Sopenharmony_ci			reg->val = intel_uncore_read64_2x32(uncore,
7662306a36Sopenharmony_ci							    entry->offset_ldw,
7762306a36Sopenharmony_ci							    entry->offset_udw);
7862306a36Sopenharmony_ci		else if (entry->size == 8 && flags == 0)
7962306a36Sopenharmony_ci			reg->val = intel_uncore_read64(uncore,
8062306a36Sopenharmony_ci						       entry->offset_ldw);
8162306a36Sopenharmony_ci		else if (entry->size == 4 && flags == 0)
8262306a36Sopenharmony_ci			reg->val = intel_uncore_read(uncore, entry->offset_ldw);
8362306a36Sopenharmony_ci		else if (entry->size == 2 && flags == 0)
8462306a36Sopenharmony_ci			reg->val = intel_uncore_read16(uncore,
8562306a36Sopenharmony_ci						       entry->offset_ldw);
8662306a36Sopenharmony_ci		else if (entry->size == 1 && flags == 0)
8762306a36Sopenharmony_ci			reg->val = intel_uncore_read8(uncore,
8862306a36Sopenharmony_ci						      entry->offset_ldw);
8962306a36Sopenharmony_ci		else
9062306a36Sopenharmony_ci			ret = -EINVAL;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return ret;
9462306a36Sopenharmony_ci}
95