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);
}
|