Skip to content

Commit 115ae87

Browse files
povikjannau
authored andcommitted
gpu: drm: apple: Expose injecting of EPIC calls via debugfs
Signed-off-by: Martin Povišer <povik+lin@cutebit.org> Co-developed-by: Janne Grunau <j@jannau.net> Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 9b62447 commit 115ae87

5 files changed

Lines changed: 206 additions & 0 deletions

File tree

drivers/gpu/drm/apple/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ config DRM_APPLE_AUDIO
1818
depends on DRM_APPLE
1919
depends on SND
2020
select SND_PCM
21+
22+
config DRM_APPLE_DEBUG
23+
bool "Enable additional driver debugging"
24+
depends on DRM_APPLE
25+
depends on EXPERT # only for developers

drivers/gpu/drm/apple/afk.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
/* Copyright 2022 Sven Peter <sven@svenpeter.dev> */
33

44
#include <linux/bitfield.h>
5+
#include <linux/debugfs.h>
56
#include <linux/dma-mapping.h>
7+
#include <linux/kconfig.h>
68
#include <linux/of_platform.h>
79
#include <linux/slab.h>
810
#include <linux/workqueue.h>
@@ -181,6 +183,18 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message,
181183
afk_send(ep, FIELD_PREP(RBEP_TYPE, RBEP_START));
182184
}
183185

186+
#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG)
187+
static void afk_populate_service_debugfs(struct apple_epic_service *srv);
188+
static void afk_remove_service_debugfs(struct apple_epic_service *srv);
189+
#else
190+
static void afk_populate_service_debugfs(struct apple_epic_service *srv)
191+
{
192+
}
193+
static void afk_remove_service_debugfs(struct apple_epic_service *srv)
194+
{
195+
}
196+
#endif
197+
184198
static const struct apple_epic_service_ops *
185199
afk_match_service(struct apple_dcp_afkep *ep, const char *name)
186200
{
@@ -284,6 +298,9 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel,
284298
ops->init(&ep->services[ch_idx], epic_name, epic_class, epic_unit);
285299
dev_info(ep->dcp->dev, "AFK[ep:%02x]: new service %s on channel %d\n",
286300
ep->endpoint, service_name, channel);
301+
302+
afk_populate_service_debugfs(&ep->services[ch_idx]);
303+
287304
free:
288305
kfree(epic_name);
289306
kfree(epic_class);
@@ -302,6 +319,8 @@ static void afk_recv_handle_teardown(struct apple_dcp_afkep *ep, u32 channel)
302319
return;
303320
}
304321

322+
afk_remove_service_debugfs(service);
323+
305324
// TODO: think through what locking is necessary
306325
spin_lock_irqsave(&service->lock, flags);
307326
service->enabled = false;
@@ -989,3 +1008,145 @@ int afk_service_call(struct apple_epic_service *service, u16 group, u32 command,
9891008
kfree(bfr);
9901009
return ret;
9911010
}
1011+
1012+
#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG)
1013+
1014+
#define AFK_DEBUGFS_MAX_REPLY 8192
1015+
1016+
static ssize_t service_call_write_file(struct file *file, const char __user *user_buf,
1017+
size_t count, loff_t *ppos)
1018+
{
1019+
struct apple_epic_service *srv = file->private_data;
1020+
void *buf;
1021+
int ret;
1022+
struct {
1023+
u32 group;
1024+
u32 command;
1025+
} call_info;
1026+
1027+
if (count < sizeof(call_info))
1028+
return -EINVAL;
1029+
if (!srv->debugfs.scratch) {
1030+
srv->debugfs.scratch = \
1031+
devm_kzalloc(srv->ep->dcp->dev, AFK_DEBUGFS_MAX_REPLY, GFP_KERNEL);
1032+
if (!srv->debugfs.scratch)
1033+
return -ENOMEM;
1034+
}
1035+
1036+
ret = copy_from_user(&call_info, user_buf, sizeof(call_info));
1037+
if (ret == sizeof(call_info))
1038+
return -EFAULT;
1039+
user_buf += sizeof(call_info);
1040+
count -= sizeof(call_info);
1041+
1042+
buf = kmalloc(count, GFP_KERNEL);
1043+
if (!buf)
1044+
return -ENOMEM;
1045+
ret = copy_from_user(buf, user_buf, count);
1046+
if (ret == count) {
1047+
kfree(buf);
1048+
return -EFAULT;
1049+
}
1050+
1051+
memset(srv->debugfs.scratch, 0, AFK_DEBUGFS_MAX_REPLY);
1052+
dma_mb();
1053+
1054+
ret = afk_service_call(srv, call_info.group, call_info.command, buf, count, 0,
1055+
srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY, 0);
1056+
kfree(buf);
1057+
1058+
if (ret < 0)
1059+
return ret;
1060+
1061+
return count + sizeof(call_info);
1062+
}
1063+
1064+
static ssize_t service_call_read_file(struct file *file, char __user *user_buf,
1065+
size_t count, loff_t *ppos)
1066+
{
1067+
struct apple_epic_service *srv = file->private_data;
1068+
1069+
if (!srv->debugfs.scratch)
1070+
return -EINVAL;
1071+
1072+
return simple_read_from_buffer(user_buf, count, ppos,
1073+
srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY);
1074+
}
1075+
1076+
static const struct file_operations service_call_fops = {
1077+
.open = simple_open,
1078+
.write = service_call_write_file,
1079+
.read = service_call_read_file,
1080+
};
1081+
1082+
static ssize_t service_raw_call_write_file(struct file *file, const char __user *user_buf,
1083+
size_t count, loff_t *ppos)
1084+
{
1085+
struct apple_epic_service *srv = file->private_data;
1086+
u32 retcode;
1087+
int ret;
1088+
1089+
if (!srv->debugfs.scratch) {
1090+
srv->debugfs.scratch = \
1091+
devm_kzalloc(srv->ep->dcp->dev, AFK_DEBUGFS_MAX_REPLY, GFP_KERNEL);
1092+
if (!srv->debugfs.scratch)
1093+
return -ENOMEM;
1094+
}
1095+
1096+
memset(srv->debugfs.scratch, 0, AFK_DEBUGFS_MAX_REPLY);
1097+
ret = copy_from_user(srv->debugfs.scratch, user_buf, count);
1098+
if (ret == count)
1099+
return -EFAULT;
1100+
1101+
ret = afk_send_command(srv, EPIC_SUBTYPE_STD_SERVICE, srv->debugfs.scratch, count,
1102+
srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY, &retcode);
1103+
if (ret < 0)
1104+
return ret;
1105+
if (retcode)
1106+
return -EINVAL;
1107+
1108+
return count;
1109+
}
1110+
1111+
static ssize_t service_raw_call_read_file(struct file *file, char __user *user_buf,
1112+
size_t count, loff_t *ppos)
1113+
{
1114+
struct apple_epic_service *srv = file->private_data;
1115+
1116+
if (!srv->debugfs.scratch)
1117+
return -EINVAL;
1118+
1119+
return simple_read_from_buffer(user_buf, count, ppos,
1120+
srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY);
1121+
}
1122+
1123+
static const struct file_operations service_raw_call_fops = {
1124+
.open = simple_open,
1125+
.write = service_raw_call_write_file,
1126+
.read = service_raw_call_read_file,
1127+
};
1128+
1129+
static void afk_populate_service_debugfs(struct apple_epic_service *srv)
1130+
{
1131+
if (!srv->ep->debugfs_entry || !srv->ops)
1132+
return;
1133+
1134+
if (strcmp(srv->ops->name, "DCPAVAudioInterface") == 0) {
1135+
srv->debugfs.entry = debugfs_create_dir(srv->ops->name,
1136+
srv->ep->debugfs_entry);
1137+
debugfs_create_file("call", 0600, srv->debugfs.entry, srv,
1138+
&service_call_fops);
1139+
debugfs_create_file("raw_call", 0600, srv->debugfs.entry, srv,
1140+
&service_raw_call_fops);
1141+
}
1142+
}
1143+
1144+
static void afk_remove_service_debugfs(struct apple_epic_service *srv)
1145+
{
1146+
if (srv->debugfs.entry) {
1147+
debugfs_remove_recursive(srv->debugfs.entry);
1148+
srv->debugfs.entry = NULL;
1149+
}
1150+
}
1151+
1152+
#endif

drivers/gpu/drm/apple/afk.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define _DRM_APPLE_DCP_AFK_H
99

1010
#include <linux/completion.h>
11+
#include <linux/kconfig.h>
1112
#include <linux/types.h>
1213

1314
#include "dcp.h"
@@ -47,6 +48,11 @@ struct apple_epic_service {
4748
bool enabled;
4849

4950
void *cookie;
51+
52+
struct {
53+
struct dentry *entry;
54+
u8 *scratch;
55+
} debugfs;
5056
};
5157

5258
enum epic_subtype;
@@ -174,6 +180,8 @@ struct apple_dcp_afkep {
174180
const struct apple_epic_service_ops *ops;
175181
struct apple_epic_service services[AFK_MAX_CHANNEL];
176182
u32 num_channels;
183+
184+
struct dentry *debugfs_entry;
177185
};
178186

179187
struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint,

drivers/gpu/drm/apple/connector.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (C) The Asahi Linux Contributors
44
*/
55

6+
#include "linux/err.h"
67
#include <linux/debugfs.h>
78
#include <linux/module.h>
89
#include <linux/seq_file.h>
@@ -77,6 +78,25 @@ CONNECTOR_DEBUGFS_ENTRY(timing, DCP_CHUNK_TIMING_ELELMENTS);
7778
CONNECTOR_DEBUGFS_ENTRY(display_attribs, DCP_CHUNK_DISPLAY_ATTRIBUTES);
7879
CONNECTOR_DEBUGFS_ENTRY(transport, DCP_CHUNK_TRANSPORT);
7980

81+
static void dcp_afk_debugfs_root(struct platform_device *pdev, int ep, struct dentry *root)
82+
{
83+
#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG)
84+
struct dentry *entry = NULL;
85+
struct apple_dcp *dcp = platform_get_drvdata(pdev);
86+
87+
switch (ep) {
88+
case AV_ENDPOINT:
89+
entry = debugfs_create_dir("avep", root);
90+
break;
91+
default:
92+
break;
93+
}
94+
95+
if (!IS_ERR_OR_NULL(entry))
96+
dcp->ep_debugfs[ep - 0x20] = entry;
97+
#endif
98+
}
99+
80100
void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry *root)
81101
{
82102
struct apple_connector *apple_con = to_apple_connector(connector);
@@ -89,6 +109,15 @@ void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry
89109
&chunk_display_attribs_fops);
90110
debugfs_create_file("Transport", 0444, root, apple_con,
91111
&chunk_transport_fops);
112+
113+
switch (connector->connector_type) {
114+
case DRM_MODE_CONNECTOR_DisplayPort:
115+
case DRM_MODE_CONNECTOR_HDMIA:
116+
dcp_afk_debugfs_root(apple_con->dcp, AV_ENDPOINT, root);
117+
break;
118+
default:
119+
break;
120+
}
92121
}
93122
EXPORT_SYMBOL(apple_connector_debugfs_init);
94123

drivers/gpu/drm/apple/dcp-internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ struct apple_dcp {
227227

228228
struct dptx_port dptxport[2];
229229

230+
/* debugfs entries */
231+
struct dentry *ep_debugfs[0x20];
232+
230233
/* these fields are output port specific */
231234
struct phy *phy;
232235
struct mux_control *xbar;

0 commit comments

Comments
 (0)