summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/xe/xe_pxp_debugfs.c
blob: 525a2f6bb0767ca583b7e995ac3f06c1a80f1b13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2024 Intel Corporation
 */

#include "xe_pxp_debugfs.h"

#include <linux/debugfs.h>

#include <drm/drm_debugfs.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>

#include "xe_device.h"
#include "xe_pxp.h"
#include "xe_pxp_types.h"
#include "regs/xe_irq_regs.h"

static struct xe_pxp *node_to_pxp(struct drm_info_node *node)
{
	return node->info_ent->data;
}

static const char *pxp_status_to_str(struct xe_pxp *pxp)
{
	lockdep_assert_held(&pxp->mutex);

	switch (pxp->status) {
	case XE_PXP_ERROR:
		return "error";
	case XE_PXP_NEEDS_TERMINATION:
		return "needs termination";
	case XE_PXP_TERMINATION_IN_PROGRESS:
		return "termination in progress";
	case XE_PXP_READY_TO_START:
		return "ready to start";
	case XE_PXP_ACTIVE:
		return "active";
	case XE_PXP_SUSPENDED:
		return "suspended";
	default:
		return "unknown";
	}
};

static int pxp_info(struct seq_file *m, void *data)
{
	struct xe_pxp *pxp = node_to_pxp(m->private);
	struct drm_printer p = drm_seq_file_printer(m);
	const char *status;

	if (!xe_pxp_is_enabled(pxp))
		return -ENODEV;

	mutex_lock(&pxp->mutex);
	status = pxp_status_to_str(pxp);

	drm_printf(&p, "status: %s\n", status);
	drm_printf(&p, "instance counter: %u\n", pxp->key_instance);
	mutex_unlock(&pxp->mutex);

	return 0;
}

static int pxp_terminate(struct seq_file *m, void *data)
{
	struct xe_pxp *pxp = node_to_pxp(m->private);
	struct drm_printer p = drm_seq_file_printer(m);
	int ready = xe_pxp_get_readiness_status(pxp);

	if (ready < 0)
		return ready; /* disabled or error occurred */
	else if (!ready)
		return -EBUSY; /* init still in progress */

	/* no need for a termination if PXP is not active */
	if (pxp->status != XE_PXP_ACTIVE) {
		drm_printf(&p, "PXP not active\n");
		return 0;
	}

	/* simulate a termination interrupt */
	spin_lock_irq(&pxp->xe->irq.lock);
	xe_pxp_irq_handler(pxp->xe, KCR_PXP_STATE_TERMINATED_INTERRUPT);
	spin_unlock_irq(&pxp->xe->irq.lock);

	drm_printf(&p, "PXP termination queued\n");

	return 0;
}

static const struct drm_info_list debugfs_list[] = {
	{"info", pxp_info, 0},
	{"terminate", pxp_terminate, 0},
};

void xe_pxp_debugfs_register(struct xe_pxp *pxp)
{
	struct drm_minor *minor;
	struct drm_info_list *local;
	struct dentry *root;
	int i;

	if (!xe_pxp_is_enabled(pxp))
		return;

	minor = pxp->xe->drm.primary;
	if (!minor->debugfs_root)
		return;

#define DEBUGFS_SIZE	(ARRAY_SIZE(debugfs_list) * sizeof(struct drm_info_list))
	local = drmm_kmalloc(&pxp->xe->drm, DEBUGFS_SIZE, GFP_KERNEL);
	if (!local)
		return;

	memcpy(local, debugfs_list, DEBUGFS_SIZE);
#undef DEBUGFS_SIZE

	for (i = 0; i < ARRAY_SIZE(debugfs_list); ++i)
		local[i].data = pxp;

	root = debugfs_create_dir("pxp", minor->debugfs_root);
	if (IS_ERR(root))
		return;

	drm_debugfs_create_files(local,
				 ARRAY_SIZE(debugfs_list),
				 root, minor);
}