Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions drivers/gpu/drm/apple/afk.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,14 +493,12 @@ static void afk_recv_handle_reply(struct apple_dcp_afkep *ep, u32 channel,
dma_free_coherent(ep->dcp->dev, txlen, txbuf, txbuf_dma);
}

/* A call from DCP: one word ahead of the call header AP sends. */
struct epic_std_service_ap_call {
__le32 unk0;
__le32 unk1;
__le32 type;
__le32 len;
__le32 magic;
u8 _unk[48];
struct epic_service_call call;
} __attribute__((packed));
static_assert(sizeof(struct epic_std_service_ap_call) == 68);

static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel,
u32 type, struct epic_hdr *ehdr,
Expand All @@ -525,30 +523,56 @@ static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel,
if (type == EPIC_TYPE_NOTIFY && eshdr->category == EPIC_CAT_NOTIFY) {
struct epic_std_service_ap_call *call = payload;
size_t call_size;
u32 command;
void *reply;
u16 group;
int ret;

if (payload_size < sizeof(*call))
return;

call_size = le32_to_cpu(call->len);
call_size = le32_to_cpu(call->call.data_len);
if (payload_size < sizeof(*call) + call_size)
return;

if (!service->ops->call)
group = le16_to_cpu(call->call.group);
command = le32_to_cpu(call->call.command);

/*
* Command numbers are per group: a group-less .call handler
* would take another group's call for a group 0 one. Without
* call_v2 there is no handler for it, and AFK cannot guess a
* reply, so it gets none, as a call without any handler.
*/
if (!service->ops->call_v2 && (group || !service->ops->call)) {
if (group)
dev_warn_ratelimited(ep->dcp->dev,
"AFK[ep:%02x]: %s (chan:%u) apcall %u:%u has no handler, sending NO reply\n",
ep->endpoint, service->ops->name,
channel, group, command);
return;
}
reply = kzalloc(payload_size, GFP_KERNEL);
if (!reply)
return;

ret = service->ops->call(service, le32_to_cpu(call->type),
payload + sizeof(*call), call_size,
reply + sizeof(*call), call_size);
if (service->ops->call_v2)
ret = service->ops->call_v2(service, group, command,
payload + sizeof(*call),
call_size,
reply + sizeof(*call),
call_size);
else
ret = service->ops->call(service, command,
payload + sizeof(*call),
call_size,
reply + sizeof(*call),
call_size);
if (ret) {
dev_warn(ep->dcp->dev,
"AFK[ep:%02x]: %s (chan:%u) apcall %u handler returned %d, sending NO reply\n",
"AFK[ep:%02x]: %s (chan:%u) apcall %u:%u handler returned %d, sending NO reply\n",
ep->endpoint, service->ops->name, channel,
le32_to_cpu(call->type), ret);
group, command, ret);
kfree(reply);
return;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/apple/afk.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct apple_epic_service_ops {
int (*call)(struct apple_epic_service *service, u32 idx,
const void *data, size_t data_size, void *reply,
size_t reply_size);
int (*call_v2)(struct apple_epic_service *service, u16 group, u32 command,
const void *data, size_t size, void *reply, size_t room);
int (*report)(struct apple_epic_service *service, enum epic_subtype type,
const void *data, size_t data_size);
void (*teardown)(struct apple_epic_service *service);
Expand Down
60 changes: 59 additions & 1 deletion drivers/gpu/drm/apple/dptxep.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx,
size_t reply_size)
{
struct dptx_port *dptx = service->cookie;
trace_dptxport_apcall(dptx, idx, data_size);
trace_dptxport_apcall(dptx, 0, idx, data_size);
dev_dbg(service->ep->dcp->dev, "DPTXPort: APCALL %u (%zu bytes)\n",
idx, data_size);
if (data_size)
Expand Down Expand Up @@ -836,11 +836,69 @@ static void dptxport_init(struct apple_epic_service *service, const char *name,
}
}

/*
* Group 1 calls 3 and 4 come around link (re)configuration, audio prepare
* included. They carry a lane count at +0x10 in (1, 3) and at +0x00 in
* (1, 4); the J700 code reads (1, 3) as drive settings with levels per
* lane from +0x20, and its group 0 GET (0, 4) has the count at +0x00.
* macOS 13 acks both with the request, (1, 3) with +0x00..0x03
* cleared and (1, 4) with +0x10..0x13 and +0x20 to the end cleared, so
* what DCP left there does not go back (42 of 42 traced pairs on t6020,
* 13.5 firmware: TV through a USB-C to HDMI adapter, Dell over TB).
*/
static int dptxport_call_group1(u32 command, const void *data,
size_t data_size, void *reply, size_t reply_size)
{
size_t size = min(reply_size, data_size);

memcpy(reply, data, size);
if (command == 3) {
memset(reply, 0, min_t(size_t, size, 0x4));
} else if (size > 0x10) {
memset(reply + 0x10, 0, min_t(size_t, size - 0x10, 0x4));
if (size > 0x20)
memset(reply + 0x20, 0, size - 0x20);
}
return 0;
}

static int dptxport_group_call(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t size,
void *reply, size_t room)
{
struct dptx_port *dptx = service->cookie;

if (!group)
return dptxport_call(service, command, data, size, reply, room);

trace_dptxport_apcall(dptx, group, command, size);
dev_dbg(service->ep->dcp->dev, "DPTXPort: APCALL %u:%u (%zu bytes)\n",
group, command, size);
if (size)
print_hex_dump_debug("DPTXPort: apcall data: ",
DUMP_PREFIX_OFFSET, 16, 1, data,
min(size, (size_t)64), true);

if (group == 1 && (command == 3 || command == 4))
return dptxport_call_group1(command, data, size, reply, room);

/*
* Echo it, as group 0 acks an unhandled call: no reply might stall
* DCP's caller.
*/
dev_warn_ratelimited(service->ep->dcp->dev,
"DPTXPort: unknown AP call %u:%u, echoing it\n",
group, command);
memcpy(reply, data, min(room, size));
return 0;
}

static const struct apple_epic_service_ops dptxep_ops[] = {
{
.name = "AppleDCPDPTXRemotePort",
.init = dptxport_init,
.call = dptxport_call,
.call_v2 = dptxport_group_call,
},
{}
};
Expand Down
17 changes: 10 additions & 7 deletions drivers/gpu/drm/apple/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,18 +398,21 @@ TRACE_EVENT(dptxport_init, TP_PROTO(struct apple_dcp *dcp, u64 unit),

TRACE_EVENT(
dptxport_apcall,
TP_PROTO(struct dptx_port *dptx, int idx, size_t len),
TP_ARGS(dptx, idx, len),
TP_PROTO(struct dptx_port *dptx, u16 group, int idx, size_t len),
TP_ARGS(dptx, group, idx, len),

TP_STRUCT__entry(__string(devname, dev_name(dptx->service->ep->dcp->dev))
__field(u32, unit) __field(int, idx) __field(size_t, len)),
__field(u32, unit) __field(u16, group) __field(int, idx)
__field(size_t, len)),

TP_fast_assign(__assign_str(devname);
__entry->unit = dptx->unit; __entry->idx = idx; __entry->len = len;),
__entry->unit = dptx->unit; __entry->group = group;
__entry->idx = idx; __entry->len = len;),

TP_printk("%s: dptx%d: AP Call %d (%s) with len %lu", __get_str(devname),
__entry->unit,
__entry->idx, show_dptxport_apcall(__entry->idx), __entry->len));
TP_printk("%s: dptx%d: AP Call %u:%d (%s) with len %lu", __get_str(devname),
__entry->unit, __entry->group, __entry->idx,
__entry->group ? "-" : show_dptxport_apcall(__entry->idx),
__entry->len));

TRACE_EVENT(
dptxport_validate_connection,
Expand Down