WIP: AFK: Support multiple endpoints with IOP initiated communication

Endpoint 0x2a (dptx-port) sees DCP initiated notify messages. Those need
to be handled with the correct endpoint context and must not be rejected
when other endpoints are polling for new messages.
This commit is contained in:
Janne Grunau 2023-02-01 13:03:07 +01:00
parent 32431d8ba1
commit 43fa9185f6
6 changed files with 122 additions and 32 deletions

124
src/afk.c
View file

@ -82,10 +82,16 @@ struct epic_cmd {
#define AFK_MAX_CHANNEL 16
struct afk_epic_ep {
int ep;
struct afk_epic {
rtkit_dev_t *rtk;
afk_epic_ep_t *endpoint[0x10];
};
struct afk_epic_ep {
int ep;
afk_epic_t *afk;
struct rtkit_buffer buf;
u16 tag;
@ -100,6 +106,8 @@ struct afk_epic_ep {
const afk_epic_service_ops_t *ops;
afk_epic_service_t services[AFK_MAX_CHANNEL];
void (*recv_handler)(afk_epic_ep_t *epic);
};
enum RBEP_MSG {
@ -148,12 +156,12 @@ bool afk_rb_init(afk_epic_ep_t *epic, struct afk_rb *rb, u64 base, u64 size)
return true;
}
static int afk_epic_poll(afk_epic_ep_t *epic)
static int afk_epic_poll(afk_epic_t *afk, int endpoint)
{
int ret;
struct rtkit_message msg;
while ((ret = rtkit_recv(epic->rtk, &msg)) == 0)
while ((ret = rtkit_recv(afk->rtk, &msg)) == 0)
;
if (ret < 0) {
@ -161,11 +169,17 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
return ret;
}
if (msg.ep != epic->ep) {
if (msg.ep < 0x20 || msg.ep >= 0x30 || !afk->endpoint[msg.ep - 0x20]) {
printf("EPIC: received message for unexpected endpoint %d\n", msg.ep);
return 0;
}
afk_epic_ep_t *epic = afk->endpoint[msg.ep - 0x20];
if (!epic) {
printf("EPIC: received message for idle endpoint %d\n", msg.ep);
return 0;
}
int type = FIELD_GET(RBEP_TYPE, msg.msg);
u64 base, size, tag;
switch (type) {
@ -175,13 +189,13 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
case RBEP_GETBUF:
size = FIELD_GET(GETBUF_SIZE, msg.msg) << BLOCK_SHIFT;
epic->tag = FIELD_GET(GETBUF_TAG, msg.msg);
if (!rtkit_alloc_buffer(epic->rtk, &epic->buf, size)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->buf, size)) {
printf("EPIC: failed to allocate buffer\n");
return -1;
}
msg.msg = (FIELD_PREP(RBEP_TYPE, RBEP_GETBUF_ACK) |
FIELD_PREP(GETBUF_ACK_DVA, epic->buf.dva));
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send buffer address\n");
return -1;
}
@ -208,7 +222,7 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
if (epic->rx.ready && epic->tx.ready) {
msg.msg = FIELD_PREP(RBEP_TYPE, RBEP_START);
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send start\n");
return -1;
}
@ -216,7 +230,11 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
break;
case RBEP_RECV:
return 1;
if (endpoint == epic->ep)
return 1;
if (epic->recv_handler)
epic->recv_handler(epic);
break;
case RBEP_START_ACK:
epic->started = true;
@ -244,7 +262,7 @@ static int afk_epic_rx(afk_epic_ep_t *epic, struct afk_qe **qe)
while (rptr == rb->hdr->wptr) {
do {
ret = afk_epic_poll(epic);
ret = afk_epic_poll(epic->afk, epic->ep);
if (ret < 0)
return ret;
} while (ret == 0);
@ -322,7 +340,7 @@ static int afk_epic_tx(afk_epic_ep_t *epic, u32 channel, u32 type, void *data, s
FIELD_PREP(RBEP_TYPE, RBEP_SEND) | FIELD_PREP(SEND_WPTR, wptr),
};
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send TX WPTR message\n");
return -1;
}
@ -547,7 +565,34 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_seq, u16 code, vo
return 0;
}
afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
static void afk_epic_notify_handler(afk_epic_ep_t *epic)
{
struct afk_qe *rmsg;
int ret = afk_epic_rx(epic, &rmsg);
if (ret < 0)
return;
if (rmsg->type != TYPE_NOTIFY) {
printf("EPIC: got unexpected message type %d in %s command\n", rmsg->type, __func__);
afk_epic_rx_ack(epic);
return;
}
struct epic_hdr *hdr = (void *)(rmsg + 1);
struct epic_sub_hdr *sub = (void *)(hdr + 1);
if (sub->category == CAT_NOTIFY && sub->type == CODE_STD_SERVICE) {
void *payload = rmsg->data + sizeof(struct epic_hdr) + sizeof(struct epic_sub_hdr);
size_t payload_size = rmsg->size - sizeof(struct epic_hdr) - sizeof(struct epic_sub_hdr);
afk_epic_handle_std_service(epic, rmsg->channel, hdr, sub, payload, payload_size);
} else
printf("EPIC: %s: rx: Ch %u, Type:0x%02x sub cat:%x type:%x \n", __func__, rmsg->channel,
rmsg->type, sub->category, sub->type);
afk_epic_rx_ack(epic);
}
afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify)
{
afk_epic_ep_t *epic = malloc(sizeof(afk_epic_ep_t));
if (!epic)
@ -555,21 +600,25 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
memset(epic, 0, sizeof(*epic));
epic->ep = endpoint;
epic->rtk = rtk;
epic->afk = afk;
afk->endpoint[endpoint - 0x20] = epic;
if (!rtkit_start_ep(rtk, endpoint)) {
if (notify)
epic->recv_handler = afk_epic_notify_handler;
if (!rtkit_start_ep(epic->afk->rtk, endpoint)) {
printf("EPIC: failed to start endpoint %d\n", endpoint);
goto err;
}
struct rtkit_message msg = {endpoint, FIELD_PREP(RBEP_TYPE, RBEP_INIT)};
if (!rtkit_send(rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send init message\n");
goto err;
}
while (!epic->started) {
int ret = afk_epic_poll(epic);
int ret = afk_epic_poll(epic->afk, endpoint);
if (ret < 0)
break;
else if (ret > 0)
@ -579,27 +628,30 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
return epic;
err:
afk->endpoint[endpoint - 0x20] = NULL;
free(epic);
return NULL;
}
int afk_epic_shutdown(afk_epic_ep_t *epic)
int afk_epic_shutdown_ep(afk_epic_ep_t *epic)
{
struct rtkit_message msg = {epic->ep, FIELD_PREP(RBEP_TYPE, RBEP_SHUTDOWN)};
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send shutdown message\n");
return -1;
}
while (epic->started) {
int ret = afk_epic_poll(epic);
int ret = afk_epic_poll(epic->afk, epic->ep);
if (ret < 0)
break;
}
rtkit_free_buffer(epic->rtk, &epic->buf);
rtkit_free_buffer(epic->rtk, &epic->rxbuf);
rtkit_free_buffer(epic->rtk, &epic->txbuf);
rtkit_free_buffer(epic->afk->rtk, &epic->buf);
rtkit_free_buffer(epic->afk->rtk, &epic->rxbuf);
rtkit_free_buffer(epic->afk->rtk, &epic->txbuf);
epic->afk->endpoint[epic->ep - 0x20] = NULL;
free(epic);
return 0;
@ -675,12 +727,12 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, const afk_epic_service_ops_t *
return -1;
}
if (!rtkit_alloc_buffer(epic->rtk, &epic->rxbuf, rxsize)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->rxbuf, rxsize)) {
printf("EPIC: failed to allocate rx buffer\n");
return -1;
}
if (!rtkit_alloc_buffer(epic->rtk, &epic->txbuf, txsize)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->txbuf, txsize)) {
printf("EPIC: failed to allocate tx buffer\n");
return -1;
}
@ -689,3 +741,27 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, const afk_epic_service_ops_t *
return channel;
}
afk_epic_t *afk_epic_init(rtkit_dev_t *rtkit)
{
afk_epic_t *afk = calloc(sizeof(*afk), 1);
if (!afk)
return NULL;
afk->rtk = rtkit;
return afk;
}
int afk_epic_shutdown(afk_epic_t *afk)
{
for (int i = 0; i < 0x10; i++)
if (afk->endpoint[i])
afk_epic_shutdown_ep(afk->endpoint[i]);
free(afk);
return 0;
}

View file

@ -9,6 +9,7 @@
#define MAX_PENDING_CMDS 8
typedef struct afk_epic afk_epic_t;
typedef struct afk_epic_ep afk_epic_ep_t;
typedef struct afk_epic_service_ops afk_epic_service_ops_t;
@ -57,8 +58,11 @@ typedef struct afk_epic_service_ops {
void *reply, size_t reply_size);
} afk_epic_service_ops_t;
afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtkit, int endpoint);
int afk_epic_shutdown(afk_epic_ep_t *epic);
afk_epic_t *afk_epic_init(rtkit_dev_t *rtkit);
int afk_epic_shutdown(afk_epic_t *afk);
afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify);
int afk_epic_shutdown_ep(afk_epic_ep_t *epic);
int afk_epic_start_channel(afk_epic_ep_t *epic, const afk_epic_service_ops_t *ops, void *intf,
const char *name);

View file

@ -60,8 +60,15 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char
goto out_iovad;
}
dcp->afk = afk_epic_init(dcp->rtkit);
if (!dcp->afk) {
printf("dcp: failed to initialize AFK\n");
goto out_rtkit;
}
return dcp;
out_rtkit:
rtkit_quiesce(dcp->rtkit);
rtkit_free(dcp->rtkit);
out_iovad:
@ -76,6 +83,7 @@ out_free:
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
{
afk_epic_shutdown(dcp->afk);
if (sleep) {
rtkit_sleep(dcp->rtkit);
pmgr_reset(0, "DISP0_CPU0");

View file

@ -3,6 +3,7 @@
#ifndef DCP_H
#define DCP_H
#include "afk.h"
#include "asc.h"
#include "dart.h"
#include "rtkit.h"
@ -32,6 +33,7 @@ typedef struct {
iova_domain_t *iovad_dcp;
asc_dev_t *asc;
rtkit_dev_t *rtkit;
afk_epic_t *afk;
dptx_port_t *port;
} dcp_dev_t;

View file

@ -500,7 +500,7 @@ dcp_dptx_if_t *dcp_dptx_init(dcp_dev_t *dcp)
return NULL;
dptx->dcp = dcp;
dptx->epic = afk_epic_init(dcp->rtkit, DCP_DPTX_ENDPOINT);
dptx->epic = afk_epic_start_ep(dcp->afk, DCP_DPTX_ENDPOINT, true);
if (!dptx->epic) {
printf("dcp-dptx: failed to initialize EPIC\n");
goto err_free;
@ -531,7 +531,7 @@ dcp_dptx_if_t *dcp_dptx_init(dcp_dev_t *dcp)
return dptx;
err_shutdown:
afk_epic_shutdown(dptx->epic);
afk_epic_shutdown_ep(dptx->epic);
err_free:
free(dptx);
return NULL;
@ -539,7 +539,7 @@ err_free:
int dcp_dptx_shutdown(dcp_dptx_if_t *dptx)
{
afk_epic_shutdown(dptx->epic);
afk_epic_shutdown_ep(dptx->epic);
free(dptx);
return 0;

View file

@ -92,7 +92,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp)
return NULL;
iboot->dcp = dcp;
iboot->epic = afk_epic_init(dcp->rtkit, DCP_IBOOT_ENDPOINT);
iboot->epic = afk_epic_start_ep(dcp->afk, DCP_IBOOT_ENDPOINT, false);
if (!iboot->epic) {
printf("dcp-iboot: failed to initialize EPIC\n");
goto err_free;
@ -109,7 +109,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp)
return iboot;
err_shutdown:
afk_epic_shutdown(iboot->epic);
afk_epic_shutdown_ep(iboot->epic);
err_free:
free(iboot);
return NULL;
@ -117,7 +117,7 @@ err_free:
int dcp_ib_shutdown(dcp_iboot_if_t *iboot)
{
afk_epic_shutdown(iboot->epic);
afk_epic_shutdown_ep(iboot->epic);
free(iboot);
return 0;