xref: /linux/drivers/gpu/drm/xe/xe_vsec.c (revision 96c84703f1cf6ea43617f9565166681cd71df104)
10c45e76fSMichael J. Ruhl // SPDX-License-Identifier: GPL-2.0
20c45e76fSMichael J. Ruhl /* Copyright © 2024 Intel Corporation */
30c45e76fSMichael J. Ruhl #include <linux/bitfield.h>
40c45e76fSMichael J. Ruhl #include <linux/bits.h>
50c45e76fSMichael J. Ruhl #include <linux/cleanup.h>
60c45e76fSMichael J. Ruhl #include <linux/errno.h>
70c45e76fSMichael J. Ruhl #include <linux/intel_vsec.h>
80c45e76fSMichael J. Ruhl #include <linux/module.h>
90c45e76fSMichael J. Ruhl #include <linux/mutex.h>
100c45e76fSMichael J. Ruhl #include <linux/pci.h>
110c45e76fSMichael J. Ruhl #include <linux/types.h>
120c45e76fSMichael J. Ruhl 
130c45e76fSMichael J. Ruhl #include "xe_device.h"
140c45e76fSMichael J. Ruhl #include "xe_device_types.h"
150c45e76fSMichael J. Ruhl #include "xe_drv.h"
160c45e76fSMichael J. Ruhl #include "xe_mmio.h"
170c45e76fSMichael J. Ruhl #include "xe_platform_types.h"
180c45e76fSMichael J. Ruhl #include "xe_pm.h"
190c45e76fSMichael J. Ruhl #include "xe_vsec.h"
200c45e76fSMichael J. Ruhl 
210c45e76fSMichael J. Ruhl #include "regs/xe_pmt.h"
220c45e76fSMichael J. Ruhl 
230c45e76fSMichael J. Ruhl /* PMT GUID value for BMG devices.  NOTE: this is NOT a PCI id */
240c45e76fSMichael J. Ruhl #define BMG_DEVICE_ID 0xE2F8
250c45e76fSMichael J. Ruhl 
260c45e76fSMichael J. Ruhl static struct intel_vsec_header bmg_telemetry = {
270c45e76fSMichael J. Ruhl 	.length = 0x10,
280c45e76fSMichael J. Ruhl 	.id = VSEC_ID_TELEMETRY,
290c45e76fSMichael J. Ruhl 	.num_entries = 2,
300c45e76fSMichael J. Ruhl 	.entry_size = 4,
310c45e76fSMichael J. Ruhl 	.tbir = 0,
320c45e76fSMichael J. Ruhl 	.offset = BMG_DISCOVERY_OFFSET,
330c45e76fSMichael J. Ruhl };
340c45e76fSMichael J. Ruhl 
350c45e76fSMichael J. Ruhl static struct intel_vsec_header bmg_punit_crashlog = {
360c45e76fSMichael J. Ruhl 	.length = 0x10,
370c45e76fSMichael J. Ruhl 	.id = VSEC_ID_CRASHLOG,
380c45e76fSMichael J. Ruhl 	.num_entries = 1,
390c45e76fSMichael J. Ruhl 	.entry_size = 4,
400c45e76fSMichael J. Ruhl 	.tbir = 0,
410c45e76fSMichael J. Ruhl 	.offset = BMG_DISCOVERY_OFFSET + 0x60,
420c45e76fSMichael J. Ruhl };
430c45e76fSMichael J. Ruhl 
440c45e76fSMichael J. Ruhl static struct intel_vsec_header bmg_oobmsm_crashlog = {
450c45e76fSMichael J. Ruhl 	.length = 0x10,
460c45e76fSMichael J. Ruhl 	.id = VSEC_ID_CRASHLOG,
470c45e76fSMichael J. Ruhl 	.num_entries = 1,
480c45e76fSMichael J. Ruhl 	.entry_size = 4,
490c45e76fSMichael J. Ruhl 	.tbir = 0,
500c45e76fSMichael J. Ruhl 	.offset = BMG_DISCOVERY_OFFSET + 0x78,
510c45e76fSMichael J. Ruhl };
520c45e76fSMichael J. Ruhl 
530c45e76fSMichael J. Ruhl static struct intel_vsec_header *bmg_capabilities[] = {
540c45e76fSMichael J. Ruhl 	&bmg_telemetry,
550c45e76fSMichael J. Ruhl 	&bmg_punit_crashlog,
560c45e76fSMichael J. Ruhl 	&bmg_oobmsm_crashlog,
570c45e76fSMichael J. Ruhl 	NULL
580c45e76fSMichael J. Ruhl };
590c45e76fSMichael J. Ruhl 
600c45e76fSMichael J. Ruhl enum xe_vsec {
610c45e76fSMichael J. Ruhl 	XE_VSEC_UNKNOWN = 0,
620c45e76fSMichael J. Ruhl 	XE_VSEC_BMG,
630c45e76fSMichael J. Ruhl };
640c45e76fSMichael J. Ruhl 
650c45e76fSMichael J. Ruhl static struct intel_vsec_platform_info xe_vsec_info[] = {
660c45e76fSMichael J. Ruhl 	[XE_VSEC_BMG] = {
670c45e76fSMichael J. Ruhl 		.caps = VSEC_CAP_TELEMETRY | VSEC_CAP_CRASHLOG,
680c45e76fSMichael J. Ruhl 		.headers = bmg_capabilities,
690c45e76fSMichael J. Ruhl 	},
700c45e76fSMichael J. Ruhl 	{ }
710c45e76fSMichael J. Ruhl };
720c45e76fSMichael J. Ruhl 
730c45e76fSMichael J. Ruhl /*
740c45e76fSMichael J. Ruhl  * The GUID will have the following bits to decode:
750c45e76fSMichael J. Ruhl  *   [0:3]   - {Telemetry space iteration number (0,1,..)}
760c45e76fSMichael J. Ruhl  *   [4:7]   - Segment (SEGMENT_INDEPENDENT-0, Client-1, Server-2)
770c45e76fSMichael J. Ruhl  *   [8:11]  - SOC_SKU
780c45e76fSMichael J. Ruhl  *   [12:27] – Device ID – changes for each down bin SKU’s
790c45e76fSMichael J. Ruhl  *   [28:29] - Capability Type (Crashlog-0, Telemetry Aggregator-1, Watcher-2)
800c45e76fSMichael J. Ruhl  *   [30:31] - Record-ID (0-PUNIT, 1-OOBMSM_0, 2-OOBMSM_1)
810c45e76fSMichael J. Ruhl  */
820c45e76fSMichael J. Ruhl #define GUID_TELEM_ITERATION	GENMASK(3, 0)
830c45e76fSMichael J. Ruhl #define GUID_SEGMENT		GENMASK(7, 4)
840c45e76fSMichael J. Ruhl #define GUID_SOC_SKU		GENMASK(11, 8)
850c45e76fSMichael J. Ruhl #define GUID_DEVICE_ID		GENMASK(27, 12)
860c45e76fSMichael J. Ruhl #define GUID_CAP_TYPE		GENMASK(29, 28)
870c45e76fSMichael J. Ruhl #define GUID_RECORD_ID		GENMASK(31, 30)
880c45e76fSMichael J. Ruhl 
890c45e76fSMichael J. Ruhl #define PUNIT_TELEMETRY_OFFSET		0x0200
900c45e76fSMichael J. Ruhl #define PUNIT_WATCHER_OFFSET		0x14A0
910c45e76fSMichael J. Ruhl #define OOBMSM_0_WATCHER_OFFSET		0x18D8
920c45e76fSMichael J. Ruhl #define OOBMSM_1_TELEMETRY_OFFSET	0x1000
930c45e76fSMichael J. Ruhl 
940c45e76fSMichael J. Ruhl enum record_id {
950c45e76fSMichael J. Ruhl 	PUNIT,
960c45e76fSMichael J. Ruhl 	OOBMSM_0,
970c45e76fSMichael J. Ruhl 	OOBMSM_1,
980c45e76fSMichael J. Ruhl };
990c45e76fSMichael J. Ruhl 
1000c45e76fSMichael J. Ruhl enum capability {
1010c45e76fSMichael J. Ruhl 	CRASHLOG,
1020c45e76fSMichael J. Ruhl 	TELEMETRY,
1030c45e76fSMichael J. Ruhl 	WATCHER,
1040c45e76fSMichael J. Ruhl };
1050c45e76fSMichael J. Ruhl 
1060c45e76fSMichael J. Ruhl static int xe_guid_decode(u32 guid, int *index, u32 *offset)
1070c45e76fSMichael J. Ruhl {
1080c45e76fSMichael J. Ruhl 	u32 record_id = FIELD_GET(GUID_RECORD_ID, guid);
1090c45e76fSMichael J. Ruhl 	u32 cap_type  = FIELD_GET(GUID_CAP_TYPE, guid);
1100c45e76fSMichael J. Ruhl 	u32 device_id = FIELD_GET(GUID_DEVICE_ID, guid);
1110c45e76fSMichael J. Ruhl 
1120c45e76fSMichael J. Ruhl 	if (device_id != BMG_DEVICE_ID)
1130c45e76fSMichael J. Ruhl 		return -ENODEV;
1140c45e76fSMichael J. Ruhl 
1150c45e76fSMichael J. Ruhl 	if (cap_type > WATCHER)
1160c45e76fSMichael J. Ruhl 		return -EINVAL;
1170c45e76fSMichael J. Ruhl 
1180c45e76fSMichael J. Ruhl 	*offset = 0;
1190c45e76fSMichael J. Ruhl 
1200c45e76fSMichael J. Ruhl 	if (cap_type == CRASHLOG) {
1210c45e76fSMichael J. Ruhl 		*index = record_id == PUNIT ? 2 : 4;
1220c45e76fSMichael J. Ruhl 		return 0;
1230c45e76fSMichael J. Ruhl 	}
1240c45e76fSMichael J. Ruhl 
1250c45e76fSMichael J. Ruhl 	switch (record_id) {
1260c45e76fSMichael J. Ruhl 	case PUNIT:
1270c45e76fSMichael J. Ruhl 		*index = 0;
1280c45e76fSMichael J. Ruhl 		if (cap_type == TELEMETRY)
1290c45e76fSMichael J. Ruhl 			*offset = PUNIT_TELEMETRY_OFFSET;
1300c45e76fSMichael J. Ruhl 		else
1310c45e76fSMichael J. Ruhl 			*offset = PUNIT_WATCHER_OFFSET;
1320c45e76fSMichael J. Ruhl 		break;
1330c45e76fSMichael J. Ruhl 
1340c45e76fSMichael J. Ruhl 	case OOBMSM_0:
1350c45e76fSMichael J. Ruhl 		*index = 1;
1360c45e76fSMichael J. Ruhl 		if (cap_type == WATCHER)
1370c45e76fSMichael J. Ruhl 			*offset = OOBMSM_0_WATCHER_OFFSET;
1380c45e76fSMichael J. Ruhl 		break;
1390c45e76fSMichael J. Ruhl 
1400c45e76fSMichael J. Ruhl 	case OOBMSM_1:
1410c45e76fSMichael J. Ruhl 		*index = 1;
1420c45e76fSMichael J. Ruhl 		if (cap_type == TELEMETRY)
1430c45e76fSMichael J. Ruhl 			*offset = OOBMSM_1_TELEMETRY_OFFSET;
1440c45e76fSMichael J. Ruhl 		break;
1450c45e76fSMichael J. Ruhl 	default:
1460c45e76fSMichael J. Ruhl 		return -EINVAL;
1470c45e76fSMichael J. Ruhl 	}
1480c45e76fSMichael J. Ruhl 
1490c45e76fSMichael J. Ruhl 	return 0;
1500c45e76fSMichael J. Ruhl }
1510c45e76fSMichael J. Ruhl 
1520c45e76fSMichael J. Ruhl static int xe_pmt_telem_read(struct pci_dev *pdev, u32 guid, u64 *data, loff_t user_offset,
1530c45e76fSMichael J. Ruhl 			     u32 count)
1540c45e76fSMichael J. Ruhl {
1550c45e76fSMichael J. Ruhl 	struct xe_device *xe = pdev_to_xe_device(pdev);
1560c45e76fSMichael J. Ruhl 	void __iomem *telem_addr = xe->mmio.regs + BMG_TELEMETRY_OFFSET;
1570c45e76fSMichael J. Ruhl 	u32 mem_region;
1580c45e76fSMichael J. Ruhl 	u32 offset;
1590c45e76fSMichael J. Ruhl 	int ret;
1600c45e76fSMichael J. Ruhl 
1610c45e76fSMichael J. Ruhl 	ret = xe_guid_decode(guid, &mem_region, &offset);
1620c45e76fSMichael J. Ruhl 	if (ret)
1630c45e76fSMichael J. Ruhl 		return ret;
1640c45e76fSMichael J. Ruhl 
1650c45e76fSMichael J. Ruhl 	telem_addr += offset + user_offset;
1660c45e76fSMichael J. Ruhl 
1670c45e76fSMichael J. Ruhl 	guard(mutex)(&xe->pmt.lock);
1680c45e76fSMichael J. Ruhl 
1690c45e76fSMichael J. Ruhl 	/* indicate that we are not at an appropriate power level */
1700c45e76fSMichael J. Ruhl 	if (!xe_pm_runtime_get_if_active(xe))
1710c45e76fSMichael J. Ruhl 		return -ENODATA;
1720c45e76fSMichael J. Ruhl 
1730c45e76fSMichael J. Ruhl 	/* set SoC re-mapper index register based on GUID memory region */
1740c45e76fSMichael J. Ruhl 	xe_mmio_rmw32(xe_root_tile_mmio(xe), SG_REMAP_INDEX1, SG_REMAP_BITS,
1750c45e76fSMichael J. Ruhl 		      REG_FIELD_PREP(SG_REMAP_BITS, mem_region));
1760c45e76fSMichael J. Ruhl 
1770c45e76fSMichael J. Ruhl 	memcpy_fromio(data, telem_addr, count);
1780c45e76fSMichael J. Ruhl 	xe_pm_runtime_put(xe);
1790c45e76fSMichael J. Ruhl 
1800c45e76fSMichael J. Ruhl 	return count;
1810c45e76fSMichael J. Ruhl }
1820c45e76fSMichael J. Ruhl 
1835cc1ccb6SMichael J. Ruhl static struct pmt_callbacks xe_pmt_cb = {
1840c45e76fSMichael J. Ruhl 	.read_telem = xe_pmt_telem_read,
1850c45e76fSMichael J. Ruhl };
1860c45e76fSMichael J. Ruhl 
1870c45e76fSMichael J. Ruhl static const int vsec_platforms[] = {
1880c45e76fSMichael J. Ruhl 	[XE_BATTLEMAGE] = XE_VSEC_BMG,
1890c45e76fSMichael J. Ruhl };
1900c45e76fSMichael J. Ruhl 
1910c45e76fSMichael J. Ruhl static enum xe_vsec get_platform_info(struct xe_device *xe)
1920c45e76fSMichael J. Ruhl {
1930c45e76fSMichael J. Ruhl 	if (xe->info.platform > XE_BATTLEMAGE)
1940c45e76fSMichael J. Ruhl 		return XE_VSEC_UNKNOWN;
1950c45e76fSMichael J. Ruhl 
1960c45e76fSMichael J. Ruhl 	return vsec_platforms[xe->info.platform];
1970c45e76fSMichael J. Ruhl }
1980c45e76fSMichael J. Ruhl 
1990c45e76fSMichael J. Ruhl /**
2000c45e76fSMichael J. Ruhl  * xe_vsec_init - Initialize resources and add intel_vsec auxiliary
2010c45e76fSMichael J. Ruhl  * interface
2020c45e76fSMichael J. Ruhl  * @xe: valid xe instance
2030c45e76fSMichael J. Ruhl  */
2040c45e76fSMichael J. Ruhl void xe_vsec_init(struct xe_device *xe)
2050c45e76fSMichael J. Ruhl {
2060c45e76fSMichael J. Ruhl 	struct intel_vsec_platform_info *info;
2070c45e76fSMichael J. Ruhl 	struct device *dev = xe->drm.dev;
2080c45e76fSMichael J. Ruhl 	struct pci_dev *pdev = to_pci_dev(dev);
2090c45e76fSMichael J. Ruhl 	enum xe_vsec platform;
2100c45e76fSMichael J. Ruhl 
2110c45e76fSMichael J. Ruhl 	platform = get_platform_info(xe);
2120c45e76fSMichael J. Ruhl 	if (platform == XE_VSEC_UNKNOWN)
2130c45e76fSMichael J. Ruhl 		return;
2140c45e76fSMichael J. Ruhl 
2150c45e76fSMichael J. Ruhl 	info = &xe_vsec_info[platform];
2160c45e76fSMichael J. Ruhl 	if (!info->headers)
2170c45e76fSMichael J. Ruhl 		return;
2180c45e76fSMichael J. Ruhl 
2190c45e76fSMichael J. Ruhl 	switch (platform) {
2200c45e76fSMichael J. Ruhl 	case XE_VSEC_BMG:
2210c45e76fSMichael J. Ruhl 		info->priv_data = &xe_pmt_cb;
2220c45e76fSMichael J. Ruhl 		break;
2230c45e76fSMichael J. Ruhl 	default:
2240c45e76fSMichael J. Ruhl 		break;
2250c45e76fSMichael J. Ruhl 	}
2260c45e76fSMichael J. Ruhl 
2270c45e76fSMichael J. Ruhl 	/*
2280c45e76fSMichael J. Ruhl 	 * Register a VSEC. Cleanup is handled using device managed
2290c45e76fSMichael J. Ruhl 	 * resources.
2300c45e76fSMichael J. Ruhl 	 */
2310c45e76fSMichael J. Ruhl 	intel_vsec_register(pdev, info);
2320c45e76fSMichael J. Ruhl }
233*bc893280SRodrigo Vivi MODULE_IMPORT_NS("INTEL_VSEC");
234