Skip to content
Closed
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
4 changes: 4 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -2018,9 +2018,13 @@ F: rust/kernel/soc/apple/aop.rs
F: sound/soc/apple/t8140_aop_audio.rs
F: tools/diagnostics/apple-dptx-training-test.c
F: tools/diagnostics/apple-j700-dp-test.c
F: tools/diagnostics/display-attributes-fixture.json
F: tools/diagnostics/test-apple-afk-admission.py
F: tools/diagnostics/test-apple-atc-unwind.py
F: tools/diagnostics/test-apple-dcp-readiness.py
F: tools/diagnostics/test-apple-display-metadata*.py
F: tools/diagnostics/test-apple-display-trace.py
F: tools/diagnostics/test-apple-external-sdr.py
F: tools/diagnostics/test-apple-j700-crossbar.py
F: tools/diagnostics/test-apple-j700-d134.py
F: tools/diagnostics/test-apple-j700-dp.py
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/apple/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ appledrm-y := apple_drv.o
appledrm-y += afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o
appledrm-$(CONFIG_DRM_APPLE_AUDIO) += audio.o
appledrm-$(CONFIG_DRM_APPLE_AUDIO) += av.o
appledrm-y += connector.o
appledrm-y += connector.o dcp-display-metadata.o
appledrm-y += ibootep.o
appledrm-y += iomfb_v12_3.o
appledrm-y += iomfb_v13_3.o
Expand Down
201 changes: 169 additions & 32 deletions drivers/gpu/drm/apple/afk.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,37 @@ int afk_start(struct apple_dcp_afkep *ep)
return 0;
}

/* Read only host-owned ring headers; never consume an entry or notify firmware. */
void afk_trace_ring_snapshot(struct apple_dcp_afkep *ep)
{
unsigned long flags;
u32 rx_rptr = 0, rx_wptr = 0, tx_rptr = 0, tx_wptr = 0;
bool rx_ready, tx_ready;

if (!ep || !ep->inline_v2 || !trace_afk_ring_snapshot_enabled())
return;
spin_lock_irqsave(&ep->lock, flags);
if (ep->stopping) {
spin_unlock_irqrestore(&ep->lock, flags);
return;
}
rx_ready = READ_ONCE(ep->rxbfr.ready) && ep->rxbfr.rptr && ep->rxbfr.wptr;
tx_ready = READ_ONCE(ep->txbfr.ready) && ep->txbfr.rptr && ep->txbfr.wptr;
dma_rmb();
if (rx_ready) {
rx_rptr = le32_to_cpu(READ_ONCE(*ep->rxbfr.rptr));
rx_wptr = le32_to_cpu(READ_ONCE(*ep->rxbfr.wptr));
}
if (tx_ready) {
tx_rptr = le32_to_cpu(READ_ONCE(*ep->txbfr.rptr));
tx_wptr = le32_to_cpu(READ_ONCE(*ep->txbfr.wptr));
}
trace_afk_ring_snapshot(ep, rx_ready, rx_rptr, rx_wptr,
READ_ONCE(ep->rxbfr.bufsz), tx_ready, tx_rptr,
tx_wptr, READ_ONCE(ep->txbfr.bufsz));
spin_unlock_irqrestore(&ep->lock, flags);
}

static void afk_getbuf(struct apple_dcp_afkep *ep, u64 message)
{
u32 size = FIELD_GET(GETBUF_SIZE, message) << BLOCK_SHIFT;
Expand Down Expand Up @@ -853,15 +884,23 @@ static void afk_v2_receive(struct apple_dcp_afkep *ep, u32 channel, u32 type,
spin_lock_irqsave(&service->lock, flags);
ret = -EPROTO;
if (slot < MAX_PENDING_CMDS && test_bit(slot, service->cmd_map) &&
!service->cmds[slot].done && response.id == service->cmds[slot].tag)
ret = afkv2_check_response(&frame, &response, service->channel,
service->cmds[slot].type, service->cmds[slot].tag,
service->cmds[slot].rxbuf_dma,
service->cmds[slot].rxlen,
service->cmds[slot].txbuf_dma,
service->cmds[slot].txlen);
if (!ret)
service->cmds[slot].reply_length = response.value ? 0 : response.rx_size;
!service->cmds[slot].done && response.id == service->cmds[slot].tag) {
struct epic_cmd_info *cmd = &service->cmds[slot];

if (ep->inline_v2)
ret = afkv2_check_inline_response(&frame, &response, service->channel,
cmd->type, cmd->tag, cmd->rxlen);
else
ret = afkv2_check_response(&frame, &response, service->channel,
cmd->type, cmd->tag, cmd->rxbuf_dma,
cmd->rxlen, cmd->txbuf_dma, cmd->txlen);
if (!ret) {
cmd->reply_length = response.value ? 0 :
(ep->inline_v2 ? response.inline_size : response.rx_size);
if (ep->inline_v2 && !response.value && cmd->reply_length)
memcpy(cmd->rxbuf, response.inline_data, cmd->reply_length);
}
}
spin_unlock_irqrestore(&service->lock, flags);
if (!ret) {
legacy.retcode = cpu_to_le32(response.value);
Expand All @@ -886,6 +925,8 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type,
u8 *payload;
size_t payload_size;

trace_afk_recv_header(ep, channel, type, data_size, data);

if (ep->wire_v2) {
afk_v2_receive(ep, channel, type, data, data_size);
return;
Expand Down Expand Up @@ -1219,20 +1260,29 @@ static int afk_send_epic_token(struct apple_dcp_afkep *ep, u32 channel, u16 tag,
return -EOPNOTSUPP;
v2_flags = 1;
} else if (ecat == EPIC_CAT_COMMAND) {
const struct epic_cmd *cmd = payload;

if (stype != EPIC_SUBTYPE_STD_SERVICE || !cmd ||
payload_len != sizeof(*cmd))
return -EINVAL;
ret = afkv2_encode_oob_command(v2_command, sizeof(v2_command), tag,
le64_to_cpu(cmd->rxbuf),
le32_to_cpu(cmd->rxlen),
le64_to_cpu(cmd->txbuf),
le32_to_cpu(cmd->txlen));
if (ret)
return ret;
payload = v2_command;
payload_len = sizeof(v2_command);
if (ep->inline_v2) {
struct afkv2_command command;

if (stype != EPIC_SUBTYPE_STD_SERVICE ||
afkv2_decode_command(payload, payload_len, &command) ||
command.oob || command.id != tag)
return -EINVAL;
} else {
const struct epic_cmd *cmd = payload;

if (stype != EPIC_SUBTYPE_STD_SERVICE || !cmd ||
payload_len != sizeof(*cmd))
return -EINVAL;
ret = afkv2_encode_oob_command(v2_command, sizeof(v2_command), tag,
le64_to_cpu(cmd->rxbuf),
le32_to_cpu(cmd->rxlen),
le64_to_cpu(cmd->txbuf),
le32_to_cpu(cmd->txlen));
if (ret)
return ret;
payload = v2_command;
payload_len = sizeof(v2_command);
}
v2_category = AFKV2_COMMAND;
} else if (ecat == EPIC_CAT_REPLY) {
v2_category = AFKV2_RESPONSE;
Expand Down Expand Up @@ -1451,12 +1501,28 @@ int afk_send_command(struct apple_epic_service *service, u8 type,
MSEC_PER_SEC);
}

static int afk_send_command_timeout_len(struct apple_epic_service *service, u8 type,
const void *payload, size_t payload_len,
void *output, size_t output_len, u32 *retcode,
unsigned int timeout_ms, size_t *received);

int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
const void *payload, size_t payload_len,
void *output, size_t output_len, u32 *retcode,
unsigned int timeout_ms)
{
return afk_send_command_timeout_len(service, type, payload, payload_len,
output, output_len, retcode, timeout_ms, NULL);
}

static int afk_send_command_timeout_len(struct apple_epic_service *service, u8 type,
const void *payload, size_t payload_len,
void *output, size_t output_len, u32 *retcode,
unsigned int timeout_ms, size_t *received)
{
struct epic_cmd cmd;
void *inline_command = NULL;
size_t copy_len = output_len;
void *rxbuf, *txbuf;
dma_addr_t rxbuf_dma, txbuf_dma;
unsigned long flags;
Expand All @@ -1465,6 +1531,8 @@ int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
struct apple_dcp_afkep *ep;
DECLARE_COMPLETION_ONSTACK(completion);

if (received)
*received = 0;
service = afk_service_get(service);
if (!service)
return -ENODEV;
Expand Down Expand Up @@ -1494,6 +1562,17 @@ int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
}

memcpy(txbuf, payload, payload_len);
if (ep->inline_v2) {
if (payload_len > AFKV2_MAX_PAYLOAD - AFKV2_COMMAND_SIZE) {
ret = -E2BIG;
goto err_free_txbuf;
}
inline_command = kmalloc(AFKV2_COMMAND_SIZE + payload_len, GFP_KERNEL);
if (!inline_command) {
ret = -ENOMEM;
goto err_free_txbuf;
}
}

memset(&cmd, 0, sizeof(cmd));
cmd.retcode = cpu_to_le32(0);
Expand Down Expand Up @@ -1531,9 +1610,21 @@ int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
service->cmds[idx].completion = &completion;
init_completion(&completion);

ret = afk_send_epic(service->ep, service->channel, tag,
EPIC_TYPE_COMMAND, EPIC_CAT_COMMAND, type, &cmd,
sizeof(cmd));
if (ep->inline_v2) {
ret = afkv2_encode_inline_command(inline_command,
AFKV2_COMMAND_SIZE + payload_len,
tag, payload, payload_len, output_len);
if (!ret)
ret = afk_send_epic(ep, service->channel, tag, EPIC_TYPE_COMMAND,
EPIC_CAT_COMMAND, type, inline_command,
AFKV2_COMMAND_SIZE + payload_len);
} else {
ret = afk_send_epic(service->ep, service->channel, tag,
EPIC_TYPE_COMMAND, EPIC_CAT_COMMAND, type, &cmd,
sizeof(cmd));
}
kfree(inline_command);
inline_command = NULL;
spin_unlock_irqrestore(&service->lock, flags);
if (ret)
goto err_free_cmd;
Expand Down Expand Up @@ -1565,13 +1656,17 @@ int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
ret = 0;
if (retcode)
*retcode = service->cmds[idx].retcode;
if (ep->inline_v2 && received)
copy_len = service->cmds[idx].reply_length;
if (ep->wire_v2 && !service->cmds[idx].retcode &&
service->cmds[idx].reply_length < output_len)
service->cmds[idx].reply_length < copy_len)
ret = -EMSGSIZE;
else if (output && output_len && (!ep->wire_v2 || !service->cmds[idx].retcode)) {
if (ep->wire_v2)
dma_rmb();
memcpy(output, rxbuf, output_len);
memcpy(output, rxbuf, copy_len);
if (received)
*received = copy_len;
}

err_free_cmd:
Expand All @@ -1580,6 +1675,8 @@ int afk_send_command_timeout(struct apple_epic_service *service, u8 type,
bitmap_release_region(service->cmd_map, idx, 0);
err_unlock:
spin_unlock_irqrestore(&service->lock, flags);
err_free_txbuf:
kfree(inline_command);
dma_free_coherent(ep->dcp->dev, payload_len, txbuf, txbuf_dma);
err_free_rxbuf:
dma_free_coherent(ep->dcp->dev, output_len, rxbuf, rxbuf_dma);
Expand All @@ -1597,19 +1694,49 @@ int afk_service_call(struct apple_epic_service *service, u16 group, u32 command,
output_pad, MSEC_PER_SEC);
}

static int afk_service_call_timeout_len(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, unsigned int timeout_ms,
size_t *received);

int afk_service_call_len(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, size_t *received)
{
return afk_service_call_timeout_len(service, group, command, data, data_len,
data_pad, output, output_len, output_pad,
MSEC_PER_SEC, received);
}

int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, unsigned int timeout_ms)
{
return afk_service_call_timeout_len(service, group, command, data, data_len,
data_pad, output, output_len, output_pad,
timeout_ms, NULL);
}

static int afk_service_call_timeout_len(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, unsigned int timeout_ms,
size_t *received)
{
struct epic_service_call *call;
size_t wire_received = 0, result_size;
void *bfr;
size_t bfr_len = max(data_len + data_pad, output_len + output_pad) +
sizeof(*call);
int ret;
u32 retcode;
u32 retlen;

if (received)
*received = 0;
if (!service)
return -ENODEV;

Expand All @@ -1622,14 +1749,17 @@ int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
memset(call, 0, sizeof(*call));
call->group = cpu_to_le16(group);
call->command = cpu_to_le32(command);
call->data_len = cpu_to_le32(data_len + data_pad);
call->data_len = cpu_to_le32(service->ep->inline_v2 ? data_len :
data_len + data_pad);
call->magic = cpu_to_le32(EPIC_SERVICE_CALL_MAGIC);

memcpy(bfr + sizeof(*call), data, data_len);

ret = afk_send_command_timeout(service, EPIC_SUBTYPE_STD_SERVICE, bfr,
bfr_len, bfr, bfr_len, &retcode,
timeout_ms);
/* Inline carries only the request; its response capacity is independent. */
ret = afk_send_command_timeout_len(service, EPIC_SUBTYPE_STD_SERVICE, bfr,
service->ep->inline_v2 ? sizeof(*call) + data_len :
bfr_len, bfr, bfr_len, &retcode, timeout_ms,
received ? &wire_received : NULL);
if (ret) {
dev_warn(service->ep->dcp->dev,
"AFK[ep:%02x]: %s (chan:%u) service call group %u cmd %u failed to complete: %d\n",
Expand All @@ -1646,6 +1776,13 @@ int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
ret = -EINVAL;
goto out;
}
if (received) {
ret = afkv2_service_reply_size(bfr, wire_received, group, command,
output_len, &result_size);
if (ret)
goto out;
*received = result_size;
}
if (le32_to_cpu(call->magic) != EPIC_SERVICE_CALL_MAGIC ||
le16_to_cpu(call->group) != group ||
le32_to_cpu(call->command) != command) {
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/apple/afk.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ struct apple_dcp_afkep {
u32 endpoint;
/* Set before afk_start; protocol selection is per endpoint. */
bool wire_v2;
/* External H17P DPAV only; other endpoints retain owned-DMA commands. */
bool inline_v2;
struct workqueue_struct *wq;

struct completion started;
Expand Down Expand Up @@ -362,6 +364,7 @@ struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint,
int afk_v2_copy_owned(struct apple_epic_service *service, u64 dva,
void *buffer, size_t size, bool to_peer);
int afk_start(struct apple_dcp_afkep *ep);
void afk_trace_ring_snapshot(struct apple_dcp_afkep *ep);
void afk_shutdown(struct apple_dcp_afkep *ep);
void afk_quiesce(struct apple_dcp_afkep *ep);
int afk_receive_message(struct apple_dcp_afkep *ep, u64 message);
Expand All @@ -382,4 +385,9 @@ int afk_service_call_timeout(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, unsigned int timeout_ms);
int afk_service_call_len(struct apple_epic_service *service, u16 group,
u32 command, const void *data, size_t data_len,
size_t data_pad, void *output, size_t output_len,
size_t output_pad, size_t *received);

#endif
Loading