uboot/arch/arm/mach-apple/rtkit.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
   4 * (C) Copyright 2021 Copyright The Asahi Linux Contributors
   5 */
   6
   7#include <common.h>
   8#include <mailbox.h>
   9#include <malloc.h>
  10
  11#include <asm/arch/rtkit.h>
  12#include <linux/apple-mailbox.h>
  13#include <linux/bitfield.h>
  14
  15#define APPLE_RTKIT_EP_MGMT 0
  16#define APPLE_RTKIT_EP_CRASHLOG 1
  17#define APPLE_RTKIT_EP_SYSLOG 2
  18#define APPLE_RTKIT_EP_DEBUG 3
  19#define APPLE_RTKIT_EP_IOREPORT 4
  20#define APPLE_RTKIT_EP_TRACEKIT 10
  21
  22/* Messages for management endpoint. */
  23#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
  24
  25#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
  26
  27#define APPLE_RTKIT_MGMT_HELLO 1
  28#define APPLE_RTKIT_MGMT_HELLO_REPLY 2
  29#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
  30#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
  31
  32#define APPLE_RTKIT_MGMT_STARTEP 5
  33#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
  34#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
  35
  36#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
  37#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
  38
  39#define APPLE_RTKIT_MGMT_EPMAP 8
  40#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
  41#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
  42#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
  43
  44#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
  45#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
  46
  47#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
  48#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
  49
  50/* Messages for internal endpoints. */
  51#define APPLE_RTKIT_BUFFER_REQUEST 1
  52#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
  53#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
  54
  55#define TIMEOUT_1SEC_US 1000000
  56
  57struct apple_rtkit {
  58        struct mbox_chan *chan;
  59        void *cookie;
  60        apple_rtkit_shmem_setup shmem_setup;
  61        apple_rtkit_shmem_destroy shmem_destroy;
  62
  63        struct apple_rtkit_buffer syslog_buffer;
  64        struct apple_rtkit_buffer crashlog_buffer;
  65        struct apple_rtkit_buffer ioreport_buffer;
  66};
  67
  68struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
  69                                     apple_rtkit_shmem_setup shmem_setup,
  70                                     apple_rtkit_shmem_destroy shmem_destroy)
  71{
  72        struct apple_rtkit *rtk;
  73
  74        rtk = calloc(sizeof(*rtk), 1);
  75        if (!rtk)
  76                return NULL;
  77
  78        rtk->chan = chan;
  79        rtk->cookie = cookie;
  80        rtk->shmem_setup = shmem_setup;
  81        rtk->shmem_destroy = shmem_destroy;
  82
  83        return rtk;
  84}
  85
  86void apple_rtkit_free(struct apple_rtkit *rtk)
  87{
  88        if (rtk->shmem_destroy) {
  89                if (rtk->syslog_buffer.buffer)
  90                        rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
  91                if (rtk->crashlog_buffer.buffer)
  92                        rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
  93                if (rtk->ioreport_buffer.buffer)
  94                        rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
  95        }
  96        free(rtk);
  97}
  98
  99static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
 100{
 101        struct apple_rtkit_buffer *buf;
 102        size_t num_4kpages;
 103        int ret;
 104
 105        num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
 106
 107        if (num_4kpages == 0) {
 108                printf("%s: unexpected request for buffer without size\n", __func__);
 109                return -1;
 110        }
 111
 112        switch (endpoint) {
 113        case APPLE_RTKIT_EP_CRASHLOG:
 114                buf = &rtk->crashlog_buffer;
 115                break;
 116        case APPLE_RTKIT_EP_SYSLOG:
 117                buf = &rtk->syslog_buffer;
 118                break;
 119        case APPLE_RTKIT_EP_IOREPORT:
 120                buf = &rtk->ioreport_buffer;
 121                break;
 122        default:
 123                printf("%s: unexpected endpoint %d\n", __func__, endpoint);
 124                return -1;
 125        }
 126
 127        buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
 128        buf->size = num_4kpages << 12;
 129        buf->is_mapped = false;
 130
 131        if (rtk->shmem_setup) {
 132                ret = rtk->shmem_setup(rtk->cookie, buf);
 133                if (ret < 0) {
 134                        printf("%s: shmen_setup failed for endpoint %d\n", __func__,
 135                               endpoint);
 136                        return ret;
 137                }
 138        }
 139
 140        if (!buf->is_mapped) {
 141                msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
 142                                FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
 143                                FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
 144                msg->msg1 = endpoint;
 145
 146                return mbox_send(rtk->chan, msg);
 147        }
 148
 149        return 0;
 150}
 151
 152int apple_rtkit_boot(struct apple_rtkit *rtk)
 153{
 154        struct apple_mbox_msg msg;
 155        int endpoints[256];
 156        int nendpoints = 0;
 157        int endpoint;
 158        int min_ver, max_ver, want_ver;
 159        int msgtype, pwrstate;
 160        u64 reply;
 161        u32 bitmap, base;
 162        int i, ret;
 163
 164        /* Wakup the IOP. */
 165        msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
 166                FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
 167        msg.msg1 = APPLE_RTKIT_EP_MGMT;
 168        ret = mbox_send(rtk->chan, &msg);
 169        if (ret < 0)
 170                return ret;
 171
 172        /* Wait for protocol version negotiation message. */
 173        ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
 174        if (ret < 0)
 175                return ret;
 176
 177        endpoint = msg.msg1;
 178        msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
 179        if (endpoint != APPLE_RTKIT_EP_MGMT) {
 180                printf("%s: unexpected endpoint %d\n", __func__, endpoint);
 181                return -EINVAL;
 182        }
 183        if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
 184                printf("%s: unexpected message type %d\n", __func__, msgtype);
 185                return -EINVAL;
 186        }
 187
 188        min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
 189        max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
 190        want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
 191
 192        if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
 193                printf("%s: firmware min version %d is too new\n",
 194                       __func__, min_ver);
 195                return -ENOTSUPP;
 196        }
 197
 198        if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
 199                printf("%s: firmware max version %d is too old\n",
 200                       __func__, max_ver);
 201                return -ENOTSUPP;
 202        }
 203
 204        /* Ack version. */
 205        msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
 206                FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
 207                FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
 208        msg.msg1 = APPLE_RTKIT_EP_MGMT;
 209        ret = mbox_send(rtk->chan, &msg);
 210        if (ret < 0)
 211                return ret;
 212
 213wait_epmap:
 214        /* Wait for endpoint map message. */
 215        ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
 216        if (ret < 0)
 217                return ret;
 218
 219        endpoint = msg.msg1;
 220        msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
 221        if (endpoint != APPLE_RTKIT_EP_MGMT) {
 222                printf("%s: unexpected endpoint %d\n", __func__, endpoint);
 223                return -EINVAL;
 224        }
 225        if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
 226                printf("%s: unexpected message type %d\n", __func__, msgtype);
 227                return -EINVAL;
 228        }
 229
 230        bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
 231        base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
 232        for (i = 0; i < 32; i++) {
 233                if (bitmap & (1U << i))
 234                        endpoints[nendpoints++] = base * 32 + i;
 235        }
 236
 237        /* Ack endpoint map. */
 238        reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
 239                FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
 240        if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
 241                reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
 242        else
 243                reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
 244        msg.msg0 = reply;
 245        msg.msg1 = APPLE_RTKIT_EP_MGMT;
 246        ret = mbox_send(rtk->chan, &msg);
 247        if (ret < 0)
 248                return ret;
 249
 250        if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
 251                goto wait_epmap;
 252
 253        for (i = 0; i < nendpoints; i++) {
 254                /* Start only necessary endpoints. The syslog endpoint is
 255                 * particularly noisy and its message can't easily be handled
 256                 * within U-Boot.
 257                 */
 258                switch (endpoints[i]) {
 259                case APPLE_RTKIT_EP_MGMT:
 260                case APPLE_RTKIT_EP_SYSLOG:
 261                case APPLE_RTKIT_EP_DEBUG:
 262                case APPLE_RTKIT_EP_TRACEKIT:
 263                        continue;
 264                default:
 265                        break;
 266                }
 267
 268                /* Request endpoint. */
 269                msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
 270                        FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
 271                        APPLE_RTKIT_MGMT_STARTEP_FLAG;
 272                msg.msg1 = APPLE_RTKIT_EP_MGMT;
 273                ret = mbox_send(rtk->chan, &msg);
 274                if (ret < 0)
 275                        return ret;
 276        }
 277
 278        pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
 279        while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
 280                ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
 281                if (ret < 0)
 282                        return ret;
 283
 284                endpoint = msg.msg1;
 285                msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
 286
 287                if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
 288                    endpoint == APPLE_RTKIT_EP_SYSLOG ||
 289                    endpoint == APPLE_RTKIT_EP_IOREPORT) {
 290                        if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
 291                                ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
 292                                if (ret < 0)
 293                                        return ret;
 294                                continue;
 295                        }
 296                }
 297
 298                if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
 299                        // these two messages have to be ack-ed for proper startup
 300                        if (msgtype == 0xc || msgtype == 0x8) {
 301                                ret = mbox_send(rtk->chan, &msg);
 302                                if (ret < 0)
 303                                        return ret;
 304                                continue;
 305                        }
 306                }
 307
 308                if (endpoint != APPLE_RTKIT_EP_MGMT) {
 309                        printf("%s: unexpected endpoint %d\n", __func__, endpoint);
 310                        return -EINVAL;
 311                }
 312                if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
 313                        printf("%s: unexpected message type %d\n", __func__, msgtype);
 314                        return -EINVAL;
 315                }
 316
 317                pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
 318        }
 319
 320        return 0;
 321}
 322
 323int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
 324{
 325        struct apple_mbox_msg msg;
 326        int ret;
 327
 328        msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
 329                FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
 330        msg.msg1 = APPLE_RTKIT_EP_MGMT;
 331        ret = mbox_send(rtk->chan, &msg);
 332        if (ret < 0)
 333                return ret;
 334
 335        ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
 336        if (ret < 0)
 337                return ret;
 338
 339        return 0;
 340}
 341