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#define _BSD_SOURCE
  27#include <stdint.h>
  28#include <stdlib.h>
  29#include <stdio.h>
  30#include <stddef.h>
  31#include <assert.h>
  32#include "hw/remote-port-proto.h"
  33
  34#undef MIN
  35#define MIN(x, y) (x < y ? x : y)
  36
  37#if defined(__linux__)
  38#  include <endian.h>
  39#elif defined(__FreeBSD__) || defined(__NetBSD__)
  40#  include <sys/endian.h>
  41#elif defined(__OpenBSD__)
  42#  include <sys/types.h>
  43#  define be16toh(x) betoh16(x)
  44#  define be32toh(x) betoh32(x)
  45#  define be64toh(x) betoh64(x)
  46#elif defined(__WIN32)
  47/* We assume little endian.  */
  48#    define htobe64(x) _byteswap_uint64(x)
  49#    define htobe32(x) _byteswap_ulong(x)
  50#    define htobe16(x) _byteswap_ushort(x)
  51
  52#    define be64toh(x) _byteswap_uint64(x)
  53#    define be32toh(x) _byteswap_ulong(x)
  54#    define be16toh(x) _byteswap_ushort(x)
  55#endif
  56
  57/* Fallback for ancient Linux systems.  */
  58#ifndef htobe64
  59#  include <byteswap.h>
  60
  61#  if __BYTE_ORDER == __LITTLE_ENDIAN
  62#    define htobe64(x) bswap_64(x)
  63#    define htobe32(x) bswap_32(x)
  64#    define htobe16(x) bswap_16(x)
  65
  66#    define be64toh(x) bswap_64(x)
  67#    define be32toh(x) bswap_32(x)
  68#    define be16toh(x) bswap_16(x)
  69#  else
  70#    define htobe64(x) x
  71#    define htobe32(x) x
  72#    define htobe16(x) x
  73
  74#    define be64toh(x) x
  75#    define be32toh(x) x
  76#    define be16toh(x) x
  77#  endif
  78#endif
  79
  80#define RP_OPT_ENT(name) [RP_OPT_ ## name] = offsetof(struct rp_cfg_state, name)
  81static const size_t rp_opt_map[] = {
  82    RP_OPT_ENT(quantum),
  83};
  84
  85static const char *rp_cmd_names[RP_CMD_max + 1] = {
  86    [RP_CMD_nop] = "nop",
  87    [RP_CMD_hello] = "hello",
  88    [RP_CMD_cfg] = "cfg",
  89    [RP_CMD_read] = "read",
  90    [RP_CMD_write] = "write",
  91    [RP_CMD_interrupt] = "interrupt",
  92    [RP_CMD_sync] = "sync",
  93};
  94
  95const char *rp_cmd_to_string(enum rp_cmd cmd)
  96{
  97    assert(cmd <= RP_CMD_max);
  98    return rp_cmd_names[cmd];
  99}
 100
 101int rp_decode_hdr(struct rp_pkt *pkt)
 102{
 103    int used = 0;
 104
 105    pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
 106    pkt->hdr.len = be32toh(pkt->hdr.len);
 107    pkt->hdr.id = be32toh(pkt->hdr.id);
 108    pkt->hdr.flags = be32toh(pkt->hdr.flags);
 109    pkt->hdr.dev = be32toh(pkt->hdr.dev);
 110    used += sizeof pkt->hdr;
 111    return used;
 112}
 113
 114int rp_decode_payload(struct rp_pkt *pkt)
 115{
 116    int used = 0;
 117
 118    switch (pkt->hdr.cmd) {
 119    case RP_CMD_hello:
 120        assert(pkt->hdr.len >= sizeof pkt->hello.version);
 121        pkt->hello.version.major = be16toh(pkt->hello.version.major);
 122        pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
 123        used += pkt->hdr.len;
 124        break;
 125    case RP_CMD_write:
 126    case RP_CMD_read:
 127        assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
 128        pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
 129        pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
 130        pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
 131        pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
 132        pkt->busaccess.len = be32toh(pkt->busaccess.len);
 133        pkt->busaccess.width = be32toh(pkt->busaccess.width);
 134        pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
 135        used += sizeof pkt->busaccess - sizeof pkt->hdr;
 136        break;
 137    case RP_CMD_interrupt:
 138        pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
 139        pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
 140        pkt->interrupt.line = be32toh(pkt->interrupt.line);
 141        pkt->interrupt.val = pkt->interrupt.val;
 142        used += pkt->hdr.len;
 143        break;
 144    case RP_CMD_sync:
 145        pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
 146        used += pkt->hdr.len;
 147        break;
 148    default:
 149        break;
 150    }
 151    return used;
 152}
 153
 154void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
 155                   uint32_t dev, uint32_t len, uint32_t flags)
 156{
 157    hdr->cmd = htobe32(cmd);
 158    hdr->len = htobe32(len);
 159    hdr->id = htobe32(id);
 160    hdr->dev = htobe32(dev);
 161    hdr->flags = htobe32(flags);
 162}
 163
 164size_t rp_encode_hello(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
 165                       uint16_t version_major, uint16_t version_minor)
 166{
 167    rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
 168                  sizeof *pkt - sizeof pkt->hdr, 0);
 169    pkt->version.major = htobe16(version_major);
 170    pkt->version.minor = htobe16(version_minor);
 171    return sizeof *pkt;
 172}
 173
 174static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
 175                                  int64_t clk, uint16_t master_id,
 176                                  uint64_t addr, uint32_t attr, uint32_t size,
 177                                  uint32_t width, uint32_t stream_width)
 178{
 179    pkt->timestamp = htobe64(clk);
 180    pkt->master_id = htobe16(master_id);
 181    pkt->addr = htobe64(addr);
 182    pkt->attributes = htobe64(attr);
 183    pkt->len = htobe32(size);
 184    pkt->width = htobe32(width);
 185    pkt->stream_width = htobe32(stream_width);
 186}
 187
 188size_t rp_encode_read(uint32_t id, uint32_t dev,
 189                      struct rp_pkt_busaccess *pkt,
 190                      int64_t clk, uint16_t master_id,
 191                      uint64_t addr, uint32_t attr, uint32_t size,
 192                      uint32_t width, uint32_t stream_width)
 193{
 194    rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
 195                  sizeof *pkt - sizeof pkt->hdr, 0);
 196    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 197                               size, width, stream_width);
 198    return sizeof *pkt;
 199}
 200
 201size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
 202                           struct rp_pkt_busaccess *pkt,
 203                           int64_t clk, uint16_t master_id,
 204                           uint64_t addr, uint32_t attr, uint32_t size,
 205                           uint32_t width, uint32_t stream_width)
 206{
 207    rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
 208                  sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
 209    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 210                               size, width, stream_width);
 211    return sizeof *pkt + size;
 212}
 213
 214size_t rp_encode_write(uint32_t id, uint32_t dev,
 215                       struct rp_pkt_busaccess *pkt,
 216                       int64_t clk, uint16_t master_id,
 217                       uint64_t addr, uint32_t attr, uint32_t size,
 218                       uint32_t width, uint32_t stream_width)
 219{
 220    rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
 221                  sizeof *pkt - sizeof pkt->hdr + size, 0);
 222    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 223                               size, width, stream_width);
 224    return sizeof *pkt;
 225}
 226
 227size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
 228                       struct rp_pkt_busaccess *pkt,
 229                       int64_t clk, uint16_t master_id,
 230                       uint64_t addr, uint32_t attr, uint32_t size,
 231                       uint32_t width, uint32_t stream_width)
 232{
 233    rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
 234                  sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
 235    rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
 236                               size, width, stream_width);
 237    return sizeof *pkt;
 238}
 239
 240size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
 241                           struct rp_pkt_interrupt *pkt,
 242                           int64_t clk,
 243                           uint32_t line, uint64_t vector, uint8_t val)
 244{
 245    rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
 246                  sizeof *pkt - sizeof pkt->hdr, 0);
 247    pkt->timestamp = htobe64(clk);
 248    pkt->vector = htobe64(vector);
 249    pkt->line = htobe32(line);
 250    pkt->val = val;
 251    return sizeof *pkt;
 252}
 253
 254static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
 255                                    struct rp_pkt_sync *pkt,
 256                                    int64_t clk, uint32_t flags)
 257{
 258    rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
 259                  sizeof *pkt - sizeof pkt->hdr, flags);
 260    pkt->timestamp = htobe64(clk);
 261    return sizeof *pkt;
 262}
 263
 264size_t rp_encode_sync(uint32_t id, uint32_t dev,
 265                      struct rp_pkt_sync *pkt,
 266                      int64_t clk)
 267{
 268    return rp_encode_sync_common(id, dev, pkt, clk, 0);
 269}
 270
 271size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
 272                           struct rp_pkt_sync *pkt,
 273                           int64_t clk)
 274{
 275    return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
 276}
 277
 278void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
 279{
 280    if (dpkt->size < size) {
 281        char *u8;
 282        dpkt->pkt = realloc(dpkt->pkt, size);
 283        u8 = (void *) dpkt->pkt;
 284        memset(u8 + dpkt->size, 0, size - dpkt->size);
 285        dpkt->size = size;
 286    }
 287}
 288
 289void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
 290{
 291    struct rp_pkt *tmp_pkt;
 292    size_t tmp_size;
 293
 294    tmp_pkt = a->pkt;
 295    tmp_size = a->size;
 296    a->pkt = b->pkt;
 297    a->size = b->size;
 298    b->pkt = tmp_pkt;
 299    b->size = tmp_size;
 300}
 301
 302bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
 303{
 304    return dpkt->size > 0 && dpkt->pkt->hdr.len;
 305}
 306
 307void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
 308{
 309    assert(rp_dpkt_is_valid(dpkt));
 310    dpkt->pkt->hdr.len = 0;
 311}
 312
 313inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
 314{
 315    dpkt->size = 0;
 316    free(dpkt->pkt);
 317}
 318