qemu/hw/core/remote-port-proto.c
<<
>>
Prefs
   1/*
   2 * Remote-port protocol
   3 *
   4 * Copyright (c) 2013 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#ifndef _DEFAULT_SOURCE
  27# define _DEFAULT_SOURCE
  28#endif
  29#include <stdint.h>
  30#include <stdlib.h>
  31#include <stdio.h>
  32#include <stddef.h>
  33#include <assert.h>
  34#include "hw/remote-port-proto.h"
  35
  36#undef MIN
  37#define MIN(x, y) (x < y ? x : y)
  38
  39#if defined(__linux__)
  40#  include <endian.h>
  41#elif defined(__FreeBSD__) || defined(__NetBSD__)
  42#  include <sys/endian.h>
  43#elif defined(__OpenBSD__)
  44#  include <sys/types.h>
  45#  define be16toh(x) betoh16(x)
  46#  define be32toh(x) betoh32(x)
  47#  define be64toh(x) betoh64(x)
  48#elif defined(__WIN32)
  49/* We assume little endian.  */
  50#    define htobe64(x) _byteswap_uint64(x)
  51#    define htobe32(x) _byteswap_ulong(x)
  52#    define htobe16(x) _byteswap_ushort(x)
  53
  54#    define be64toh(x) _byteswap_uint64(x)
  55#    define be32toh(x) _byteswap_ulong(x)
  56#    define be16toh(x) _byteswap_ushort(x)
  57#endif
  58
  59/* Fallback for ancient Linux systems.  */
  60#ifndef htobe64
  61#  include <byteswap.h>
  62
  63#  if __BYTE_ORDER == __LITTLE_ENDIAN
  64#    define htobe64(x) bswap_64(x)
  65#    define htobe32(x) bswap_32(x)
  66#    define htobe16(x) bswap_16(x)
  67
  68#    define be64toh(x) bswap_64(x)
  69#    define be32toh(x) bswap_32(x)
  70#    define be16toh(x) bswap_16(x)
  71#  else
  72#    define htobe64(x) x
  73#    define htobe32(x) x
  74#    define htobe16(x) x
  75
  76#    define be64toh(x) x
  77#    define be32toh(x) x
  78#    define be16toh(x) x
  79#  endif
  80#endif
  81
  82static const char *rp_cmd_names[RP_CMD_max + 1] = {
  83    [RP_CMD_nop] = "nop",
  84    [RP_CMD_hello] = "hello",
  85    [RP_CMD_cfg] = "cfg",
  86    [RP_CMD_read] = "read",
  87    [RP_CMD_write] = "write",
  88    [RP_CMD_interrupt] = "interrupt",
  89    [RP_CMD_sync] = "sync",
  90};
  91
  92const char *rp_cmd_to_string(enum rp_cmd cmd)
  93{
  94    assert(cmd <= RP_CMD_max);
  95    return rp_cmd_names[cmd];
  96}
  97
  98int rp_decode_hdr(struct rp_pkt *pkt)
  99{
 100    int used = 0;
 101
 102    pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
 103    pkt->hdr.len = be32toh(pkt->hdr.len);
 104    pkt->hdr.id = be32toh(pkt->hdr.id);
 105    pkt->hdr.flags = be32toh(pkt->hdr.flags);
 106    pkt->hdr.dev = be32toh(pkt->hdr.dev);
 107    used += sizeof pkt->hdr;
 108    return used;
 109}
 110
 111int rp_decode_payload(struct rp_pkt *pkt)
 112{
 113    int used = 0;
 114    /* Master_id has an odd decoding due to historical reasons.  */
 115    uint64_t master_id;
 116
 117    switch (pkt->hdr.cmd) {
 118    case RP_CMD_hello:
 119        assert(pkt->hdr.len >= sizeof pkt->hello.version);
 120        pkt->hello.version.major = be16toh(pkt->hello.version.major);
 121        pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
 122        used += sizeof pkt->hello.version;
 123
 124        if ((pkt->hdr.len - used) >= sizeof pkt->hello.caps) {
 125            void *offset;
 126            int i;
 127
 128            pkt->hello.caps.offset = be32toh(pkt->hello.caps.offset);
 129            pkt->hello.caps.len = be16toh(pkt->hello.caps.len);
 130
 131            offset = (char *)pkt + pkt->hello.caps.offset;
 132            for (i = 0; i < pkt->hello.caps.len; i++) {
 133                uint32_t cap;
 134
 135                /* We don't know if offset is 32bit aligned so use
 136                 * memcpy to do the endian conversion.  */
 137                memcpy(&cap, offset + i * sizeof cap, sizeof cap);
 138                cap = be32toh(cap);
 139                memcpy(offset + i * sizeof cap, &cap, sizeof cap);
 140            }
 141            used += sizeof pkt->hello.caps;
 142        } else {
 143            pkt->hello.caps.offset = 0;
 144            pkt->hello.caps.len = 0;
 145        }
 146
 147        /* Consume everything ignoring additional headers we do not yet
 148         * know about.  */
 149        used = pkt->hdr.len;
 150        break;
 151    case RP_CMD_write:
 152    case RP_CMD_read:
 153        assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
 154        pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
 155        pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
 156        pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
 157        pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
 158        pkt->busaccess.len = be32toh(pkt->busaccess.len);
 159        pkt->busaccess.width = be32toh(pkt->busaccess.width);
 160        pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
 161        master_id = be16toh(pkt->busaccess.master_id);
 162
 163        used += sizeof pkt->busaccess - sizeof pkt->hdr;
 164
 165        if (pkt->busaccess.attributes & RP_BUS_ATTR_EXT_BASE) {
 166            struct rp_pkt_busaccess_ext_base *pext = &pkt->busaccess_ext_base;
 167
 168            assert(pkt->hdr.len >= sizeof *pext - sizeof pkt->hdr);
 169            master_id |= (uint64_t)be16toh(pext->master_id_31_16) << 16;
 170            master_id |= (uint64_t)be32toh(pext->master_id_63_32) << 32;
 171            pext->data_offset = be32toh(pext->data_offset);
 172            pext->next_offset = be32toh(pext->next_offset);
 173            pext->byte_enable_offset = be32toh(pext->byte_enable_offset);
 174            pext->byte_enable_len = be32toh(pext->byte_enable_len);
 175
 176            used += sizeof *pext - sizeof pkt->busaccess;
 177        }
 178        pkt->busaccess.master_id = master_id;
 179        break;
 180    case RP_CMD_interrupt:
 181        pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
 182        pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
 183        pkt->interrupt.line = be32toh(pkt->interrupt.line);
 184        pkt->interrupt.val = pkt->interrupt.val;
 185        used += pkt->hdr.len;
 186        break;
 187    case RP_CMD_sync:
 188        pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
 189        used += pkt->hdr.len;
 190        break;
 191    default:
 192        break;
 193    }
 194    return used;
 195}
 196
 197void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
 198                   uint32_t dev, uint32_t len, uint32_t flags)
 199{
 200    hdr->cmd = htobe32(cmd);
 201    hdr->len = htobe32(len);
 202    hdr->id = htobe32(id);
 203    hdr->dev = htobe32(dev);
 204    hdr->flags = htobe32(flags);
 205}
 206
 207size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
 208                            uint16_t version_major, uint16_t version_minor,
 209                            uint32_t *caps, uint32_t *caps_out,
 210                            uint32_t caps_len)
 211{
 212    size_t psize = sizeof *pkt + sizeof caps[0] * caps_len;
 213    unsigned int i;
 214
 215    rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
 216                  psize - sizeof pkt->hdr, 0);
 217    pkt->version.major = htobe16(version_major);
 218    pkt->version.minor = htobe16(version_minor);
 219
 220    /* Feature list is appeneded right after the hello packet.  */
 221    pkt->caps.offset = htobe32(sizeof *pkt);
 222    pkt->caps.len = htobe16(caps_len);
 223
 224    for (i = 0; i < caps_len; i++) {
 225        uint32_t cap;
 226
 227        cap = caps[i];
 228        caps_out[i] = htobe32(cap);
 229    }
 230    return sizeof *pkt;
 231}
 232
 233static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
 234                                  int64_t clk, uint16_t master_id,
 235                                  uint64_t addr, uint64_t attr, uint32_t size,
 236                                  uint32_t width, uint32_t stream_width)
 237{
 238    pkt->timestamp = htobe64(clk);
 239    pkt->master_id = htobe16(master_id);
 240    pkt->addr = htobe64(addr);
 241    pkt->attributes = htobe64(attr);
 242    pkt->len = htobe32(size);
 243    pkt->width = htobe32(width);
 244    pkt->stream_width = htobe32(stream_width);
 245}
 246
 247size_t rp_encode_read(uint32_t id, uint32_t dev,
 248                      struct rp_pkt_busaccess *pkt,
 249                      int64_t clk, uint16_t master_id,
 250                      uint64_t addr, uint64_t attr, uint32_t size,
 251                      uint32_t width, uint32_t stream_width)
 252{
 253    rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
 254                  sizeof *pkt - sizeof pkt->hdr, 0);
 255    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 256                               size, width, stream_width);
 257    return sizeof *pkt;
 258}
 259
 260size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
 261                           struct rp_pkt_busaccess *pkt,
 262                           int64_t clk, uint16_t master_id,
 263                           uint64_t addr, uint64_t attr, uint32_t size,
 264                           uint32_t width, uint32_t stream_width)
 265{
 266    rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
 267                  sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
 268    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 269                               size, width, stream_width);
 270    return sizeof *pkt + size;
 271}
 272
 273size_t rp_encode_write(uint32_t id, uint32_t dev,
 274                       struct rp_pkt_busaccess *pkt,
 275                       int64_t clk, uint16_t master_id,
 276                       uint64_t addr, uint64_t attr, uint32_t size,
 277                       uint32_t width, uint32_t stream_width)
 278{
 279    rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
 280                  sizeof *pkt - sizeof pkt->hdr + size, 0);
 281    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 282                               size, width, stream_width);
 283    return sizeof *pkt;
 284}
 285
 286size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
 287                       struct rp_pkt_busaccess *pkt,
 288                       int64_t clk, uint16_t master_id,
 289                       uint64_t addr, uint64_t attr, uint32_t size,
 290                       uint32_t width, uint32_t stream_width)
 291{
 292    rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
 293                  sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
 294    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 295                               size, width, stream_width);
 296    return sizeof *pkt;
 297}
 298
 299/* New API for extended header.  */
 300size_t rp_encode_busaccess(struct rp_peer_state *peer,
 301                           struct rp_pkt_busaccess_ext_base *pkt,
 302                           struct rp_encode_busaccess_in *in) {
 303    struct rp_pkt_busaccess *pkt_v4_0 = (void *) pkt;
 304    uint32_t hsize = 0;
 305    uint32_t ret_size = 0;
 306
 307    /* Allocate packet space.  */
 308    if (in->cmd == RP_CMD_write && !(in->flags & RP_PKT_FLAGS_response)) {
 309        hsize = in->size;
 310    }
 311    if (in->cmd == RP_CMD_read && (in->flags & RP_PKT_FLAGS_response)) {
 312        hsize = in->size;
 313        ret_size = in->size;
 314    }
 315
 316    /* If peer does not support the busaccess base extensions, use the
 317     * old layout. For responses, what matters is if we're responding
 318     * to a packet with the extensions.
 319     */
 320    if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
 321        /* Old layout.  */
 322        assert(in->master_id < UINT16_MAX);
 323
 324        rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
 325                  sizeof *pkt_v4_0 - sizeof pkt->hdr + hsize, in->flags);
 326        rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id,
 327                                   in->addr, in->attr,
 328                                   in->size, in->width, in->stream_width);
 329        return sizeof *pkt_v4_0 + ret_size;
 330    }
 331
 332    /* Encode the extended fields.  */
 333    pkt->master_id_31_16 = htobe16(in->master_id >> 16);
 334    pkt->master_id_63_32 = htobe32(in->master_id >> 32);
 335
 336    /* We always put data right after the header.  */
 337    pkt->data_offset = htobe32(sizeof *pkt);
 338    pkt->next_offset = 0;
 339
 340    pkt->byte_enable_offset = htobe32(sizeof *pkt + hsize);
 341    pkt->byte_enable_len = htobe32(in->byte_enable_len);
 342    hsize += in->byte_enable_len;
 343
 344    rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
 345                  sizeof *pkt - sizeof pkt->hdr + hsize, in->flags);
 346    rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id, in->addr,
 347                               in->attr | RP_BUS_ATTR_EXT_BASE,
 348                               in->size, in->width, in->stream_width);
 349
 350    return sizeof *pkt + ret_size;
 351}
 352
 353size_t rp_encode_interrupt_f(uint32_t id, uint32_t dev,
 354                             struct rp_pkt_interrupt *pkt,
 355                             int64_t clk,
 356                             uint32_t line, uint64_t vector, uint8_t val,
 357                             uint32_t flags)
 358{
 359    rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
 360                  sizeof *pkt - sizeof pkt->hdr, flags);
 361    pkt->timestamp = htobe64(clk);
 362    pkt->vector = htobe64(vector);
 363    pkt->line = htobe32(line);
 364    pkt->val = val;
 365    return sizeof *pkt;
 366}
 367
 368size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
 369                           struct rp_pkt_interrupt *pkt,
 370                           int64_t clk,
 371                           uint32_t line, uint64_t vector, uint8_t val)
 372{
 373    return rp_encode_interrupt_f(id, dev, pkt, clk, line, vector, val, 0);
 374}
 375
 376static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
 377                                    struct rp_pkt_sync *pkt,
 378                                    int64_t clk, uint32_t flags)
 379{
 380    rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
 381                  sizeof *pkt - sizeof pkt->hdr, flags);
 382    pkt->timestamp = htobe64(clk);
 383    return sizeof *pkt;
 384}
 385
 386size_t rp_encode_sync(uint32_t id, uint32_t dev,
 387                      struct rp_pkt_sync *pkt,
 388                      int64_t clk)
 389{
 390    return rp_encode_sync_common(id, dev, pkt, clk, 0);
 391}
 392
 393size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
 394                           struct rp_pkt_sync *pkt,
 395                           int64_t clk)
 396{
 397    return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
 398}
 399
 400void rp_process_caps(struct rp_peer_state *peer,
 401                     void *caps, size_t caps_len)
 402{
 403    int i;
 404
 405    assert(peer->caps.busaccess_ext_base == false);
 406
 407    for (i = 0; i < caps_len; i++) {
 408        uint32_t cap;
 409
 410        memcpy(&cap, caps + i * sizeof cap, sizeof cap);
 411
 412        switch (cap) {
 413        case CAP_BUSACCESS_EXT_BASE:
 414            peer->caps.busaccess_ext_base = true;
 415            break;
 416        case CAP_BUSACCESS_EXT_BYTE_EN:
 417            peer->caps.busaccess_ext_byte_en = true;
 418            break;
 419        case CAP_WIRE_POSTED_UPDATES:
 420            peer->caps.wire_posted_updates = true;
 421            break;
 422        }
 423    }
 424}
 425
 426
 427void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
 428{
 429    if (dpkt->size < size) {
 430        char *u8;
 431        dpkt->pkt = realloc(dpkt->pkt, size);
 432        u8 = (void *) dpkt->pkt;
 433        memset(u8 + dpkt->size, 0, size - dpkt->size);
 434        dpkt->size = size;
 435    }
 436}
 437
 438void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
 439{
 440    struct rp_pkt *tmp_pkt;
 441    size_t tmp_size;
 442
 443    tmp_pkt = a->pkt;
 444    tmp_size = a->size;
 445    a->pkt = b->pkt;
 446    a->size = b->size;
 447    b->pkt = tmp_pkt;
 448    b->size = tmp_size;
 449}
 450
 451bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
 452{
 453    return dpkt->size > 0 && dpkt->pkt->hdr.len;
 454}
 455
 456void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
 457{
 458    assert(rp_dpkt_is_valid(dpkt));
 459    dpkt->pkt->hdr.len = 0;
 460}
 461
 462inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
 463{
 464    dpkt->size = 0;
 465    free(dpkt->pkt);
 466}
 467