qemu/hw/core/remote-port-pci-device.c
<<
>>
Prefs
   1/*
   2 * QEMU remote port PCI device.
   3 *
   4 * Copyright (c) 2016-2020 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * This code is licensed under the GNU GPL.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "sysemu/sysemu.h"
  12#include "qemu/log.h"
  13#include "qapi/qmp/qerror.h"
  14#include "qapi/error.h"
  15#include "hw/pci/pci.h"
  16#include "hw/pci/msi.h"
  17#include "hw/pci/msix.h"
  18#include "hw/sysbus.h"
  19#include "migration/vmstate.h"
  20#include "hw/qdev-properties.h"
  21
  22#include "hw/remote-port.h"
  23#include "hw/remote-port-device.h"
  24#include "hw/remote-port-memory-master.h"
  25#include "hw/remote-port-memory-slave.h"
  26
  27#include "hw/fdt_generic_util.h"
  28
  29#ifndef REMOTE_PORT_ERR_DEBUG
  30#define REMOTE_PORT_DEBUG_LEVEL 0
  31#else
  32#define REMOTE_PORT_DEBUG_LEVEL 1
  33#endif
  34
  35#define DB_PRINT_L(level, ...) do { \
  36    if (REMOTE_PORT_DEBUG_LEVEL > level) { \
  37        fprintf(stderr,  ": %s: ", __func__); \
  38        fprintf(stderr, ## __VA_ARGS__); \
  39    } \
  40} while (0);
  41
  42#define TYPE_REMOTE_PORT_PCI_DEVICE "remote-port-pci-device"
  43#define REMOTE_PORT_PCI_DEVICE(obj) \
  44        OBJECT_CHECK(RemotePortPCIDevice, (obj), \
  45                     TYPE_REMOTE_PORT_PCI_DEVICE)
  46
  47#define REMOTE_PORT_PCI_DEVICE_PARENT_CLASS \
  48    object_class_get_parent( \
  49            object_class_by_name(TYPE_REMOTE_PORT_PCI_DEVICE))
  50
  51/*
  52 * RP-dev allocation.
  53 *
  54 * We allocate 20 RP devices for a single PCIe device.
  55 * dev          Function
  56 * 0            Config space
  57 * 1            Legacy IRQ
  58 * 2            Reserved for Messages
  59 * 3            DMA from the End-point towards us.
  60 * 4 - 9        Reserved
  61 * 10 - 20      IO or Memory Mapped BARs (6 + 4 reserved)
  62 */
  63#define RPDEV_PCI_CONFIG        0
  64#define RPDEV_PCI_LEGACY_IRQ    1
  65#define RPDEV_PCI_MESSAGES      2
  66#define RPDEV_PCI_DMA           3
  67#define RPDEV_PCI_BAR_BASE     10
  68
  69typedef struct RemotePortPCIDevice RemotePortPCIDevice;
  70
  71struct RemotePortPCIDevice {
  72    /*< private >*/
  73    PCIDevice parent_obj;
  74
  75    RemotePortMemorySlave *rp_dma;
  76
  77    /*< public >*/
  78    RemotePortMap *maps;
  79
  80    struct {
  81        uint32_t rp_dev;
  82        uint32_t nr_io_bars;
  83        uint32_t nr_mm_bars;
  84        uint64_t bar_size[6];
  85        uint32_t nr_devs;
  86        uint32_t vendor_id;
  87        uint32_t device_id;
  88        uint32_t revision;
  89        uint32_t class_id;
  90        uint8_t prog_if;
  91        uint8_t irq_pin;
  92
  93        /* Controls if the remote dev is responsible for the config space.  */
  94        bool remote_config;
  95
  96        bool msi;
  97        bool msix;
  98    } cfg;
  99    struct RemotePort *rp;
 100    struct rp_peer_state *peer;
 101};
 102
 103static void rp_io_access(MemoryTransaction *tr)
 104{
 105    RemotePortMap *map = tr->opaque;
 106    RemotePortPCIDevice *s = map->parent;
 107
 108    rp_mm_access(s->rp, map->rp_dev, s->peer, tr, true, 0);
 109}
 110
 111static const MemoryRegionOps rp_ops = {
 112    .access = rp_io_access,
 113    .endianness = DEVICE_LITTLE_ENDIAN,
 114};
 115
 116static uint32_t rp_pci_read_config(PCIDevice *pci_dev, uint32_t addr, int size)
 117{
 118    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
 119    MemoryTransaction tr = {
 120        .addr = addr,
 121        .rw = false,
 122        .size = size,
 123        .attr = MEMTXATTRS_UNSPECIFIED
 124    };
 125
 126    rp_mm_access(s->rp, s->cfg.rp_dev, s->peer, &tr, true, 0);
 127    DB_PRINT_L(0, "addr: %x data: %x\n", addr, (uint32_t) tr.data.u64);
 128    return tr.data.u64;
 129}
 130
 131static void rp_pci_write_config(PCIDevice *pci_dev, uint32_t addr,
 132                                uint32_t value, int size)
 133{
 134    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
 135    MemoryTransaction tr = {
 136        .addr = addr,
 137        .rw = true,
 138        .size = size,
 139        .data.u64 = value,
 140        .attr = MEMTXATTRS_UNSPECIFIED
 141    };
 142
 143    DB_PRINT_L(0, "addr: %x data: %x\n", addr, value);
 144    rp_mm_access(s->rp, s->cfg.rp_dev, s->peer, &tr, true, 0);
 145    pci_default_write_config(pci_dev, addr, value, size);
 146    DB_PRINT_L(1, "\n");
 147}
 148
 149static void rp_gpio_interrupt(RemotePortDevice *rpd, struct rp_pkt *pkt)
 150{
 151    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(rpd);
 152    PCIDevice *d = PCI_DEVICE(s);
 153    int irq = pkt->interrupt.line;
 154    int level = pkt->interrupt.val;
 155
 156    DB_PRINT_L(0, "%s: irq[%d]=%d\n", __func__, irq, level);
 157
 158    /*
 159     * If MSI/MSI-X is enabled, map interrupt wires onto MSI.
 160     * This will only work when QEMU owns the CONFIG space.
 161     */
 162    if (s->cfg.msix && msix_enabled(d)) {
 163        if (level) {
 164            msix_notify(d, 0);
 165        }
 166    } else if (s->cfg.msi && msi_enabled(d)) {
 167        if (level) {
 168            msi_notify(d, 0);
 169        }
 170    } else {
 171        pci_set_irq(d, level);
 172    }
 173}
 174
 175static void rp_pci_realize(PCIDevice *pci_dev, Error **errp)
 176{
 177    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
 178    AddressSpace *as;
 179    int i;
 180
 181    assert(s->rp);
 182    s->peer = rp_get_peer(s->rp);
 183
 184    /* Update device IDs after our properties have been set.  */
 185    pci_config_set_vendor_id(pci_dev->config, s->cfg.vendor_id);
 186    pci_config_set_device_id(pci_dev->config, s->cfg.device_id);
 187    pci_config_set_revision(pci_dev->config, s->cfg.revision);
 188    pci_config_set_class(pci_dev->config, s->cfg.class_id);
 189    pci_dev->config[PCI_CLASS_PROG] = s->cfg.prog_if;
 190    pci_dev->config[PCI_INTERRUPT_PIN] = s->cfg.irq_pin;
 191
 192    if (s->cfg.remote_config) {
 193        pci_dev->config_read = rp_pci_read_config;
 194    }
 195    /* The remote peer may want to snoop on CFG writes.  */
 196    pci_dev->config_write = rp_pci_write_config;
 197
 198    if (s->cfg.msi) {
 199        msi_init(pci_dev, 0x60, 1, true, false, &error_fatal);
 200    }
 201
 202    /* Create and hook up the BARs.  */
 203    s->maps = g_new0(typeof(*s->maps), s->cfg.nr_io_bars + s->cfg.nr_mm_bars);
 204
 205    for (i = 0; i < s->cfg.nr_io_bars + s->cfg.nr_mm_bars; i++) {
 206        bool io_bar = i < s->cfg.nr_io_bars;
 207        char *name = g_strdup_printf("rp-pci-%s-%d", io_bar ? "io" : "mmio", i);
 208        uint8_t attr = io_bar ?
 209               PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
 210
 211        memory_region_init_io(&s->maps[i].iomem, OBJECT(s), &rp_ops,
 212                              &s->maps[i], name, s->cfg.bar_size[i]);
 213        pci_register_bar(pci_dev, i, attr, &s->maps[i].iomem);
 214        s->maps[i].rp_dev = RPDEV_PCI_BAR_BASE + i;
 215        s->maps[i].parent = s;
 216        g_free(name);
 217    }
 218
 219    if (s->cfg.msix) {
 220        msix_init_exclusive_bar(pci_dev, 1,
 221                                s->cfg.nr_io_bars + s->cfg.nr_mm_bars,
 222                                NULL);
 223        msix_vector_use(pci_dev, 0);
 224    }
 225
 226    /* Setup the DMA dev.  */
 227    rp_device_attach(OBJECT(s->rp), OBJECT(s->rp_dma), 0,
 228                            s->cfg.rp_dev + RPDEV_PCI_DMA, &error_abort);
 229
 230    as = pci_get_address_space(pci_dev);
 231    object_property_set_link(OBJECT(s->rp_dma), OBJECT(as->root), "mr",
 232                             &error_abort);
 233
 234    object_property_set_bool(OBJECT(s->rp_dma), true, "realized", &error_abort);
 235}
 236
 237static void rp_pci_exit(PCIDevice *pci_dev)
 238{
 239    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(pci_dev);
 240
 241    /* Setup the DMA dev.  */
 242    rp_device_detach(OBJECT(s->rp), OBJECT(s->rp_dma), 0,
 243                            s->cfg.rp_dev + RPDEV_PCI_DMA, &error_abort);
 244    rp_device_detach(OBJECT(s->rp), OBJECT(s), 0,
 245                            s->cfg.rp_dev, &error_abort);
 246
 247    /*
 248     * Cannot be a child of us since as->root->owner gets reffed by
 249     * address_space_init in rp_dma creating a circular dep.
 250     */
 251    object_unparent(OBJECT(s->rp_dma));
 252}
 253
 254static void rp_pci_init(Object *obj)
 255{
 256    RemotePortPCIDevice *s = REMOTE_PORT_PCI_DEVICE(obj);
 257    Object *tmp_obj;
 258
 259    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 260                             (Object **)&s->rp,
 261                             qdev_prop_allow_set_link,
 262                             OBJ_PROP_LINK_STRONG);
 263
 264
 265    tmp_obj = object_new(TYPE_REMOTE_PORT_MEMORY_SLAVE);
 266    s->rp_dma = REMOTE_PORT_MEMORY_SLAVE(tmp_obj);
 267
 268    object_property_add_child(obj, "rp-dma", tmp_obj);
 269    /* add_child will grant us another ref, free the initial one.  */
 270    object_unref(tmp_obj);
 271}
 272
 273static Property rp_properties[] = {
 274    DEFINE_PROP_UINT32("rp-chan0", RemotePortPCIDevice, cfg.rp_dev, 0),
 275    DEFINE_PROP_UINT32("nr-io-bars", RemotePortPCIDevice, cfg.nr_io_bars, 0),
 276    DEFINE_PROP_UINT32("nr-mm-bars", RemotePortPCIDevice, cfg.nr_mm_bars, 0),
 277    DEFINE_PROP_UINT32("vendor-id", RemotePortPCIDevice, cfg.vendor_id, 0),
 278    DEFINE_PROP_UINT32("device-id", RemotePortPCIDevice, cfg.device_id, 0),
 279    DEFINE_PROP_UINT32("revision", RemotePortPCIDevice, cfg.revision, 0),
 280    DEFINE_PROP_UINT32("class-id", RemotePortPCIDevice, cfg.class_id, 0),
 281    DEFINE_PROP_UINT8("prog-if", RemotePortPCIDevice, cfg.prog_if, 1),
 282    DEFINE_PROP_UINT8("irq-pin", RemotePortPCIDevice, cfg.irq_pin, 1),
 283
 284    DEFINE_PROP_UINT64("bar-size0", RemotePortPCIDevice,
 285                                    cfg.bar_size[0], 0x1000),
 286    DEFINE_PROP_UINT64("bar-size1", RemotePortPCIDevice,
 287                                    cfg.bar_size[1], 0x1000),
 288    DEFINE_PROP_UINT64("bar-size2", RemotePortPCIDevice,
 289                                    cfg.bar_size[2], 0x1000),
 290    DEFINE_PROP_UINT64("bar-size3", RemotePortPCIDevice,
 291                                    cfg.bar_size[3], 0x1000),
 292    DEFINE_PROP_UINT64("bar-size4", RemotePortPCIDevice,
 293                                    cfg.bar_size[4], 0x1000),
 294    DEFINE_PROP_UINT64("bar-size5", RemotePortPCIDevice,
 295                                    cfg.bar_size[5], 0x1000),
 296
 297    DEFINE_PROP_BOOL("remote-config", RemotePortPCIDevice,
 298                     cfg.remote_config, false),
 299    DEFINE_PROP_BOOL("msi", RemotePortPCIDevice, cfg.msi, false),
 300    DEFINE_PROP_BOOL("msix", RemotePortPCIDevice, cfg.msix, false),
 301
 302    /* These are read-only.  */
 303    DEFINE_PROP_UINT32("nr-devs", RemotePortPCIDevice, cfg.nr_devs, 20),
 304    DEFINE_PROP_END_OF_LIST()
 305};
 306
 307static void rp_pci_class_init(ObjectClass *oc, void *data)
 308{
 309    RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
 310    DeviceClass *dc = DEVICE_CLASS(oc);
 311    PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
 312
 313    dc->desc = "Remote-Port PCI Device";
 314    device_class_set_props(dc, rp_properties);
 315
 316    rpdc->ops[RP_CMD_interrupt] = rp_gpio_interrupt;
 317    k->realize = rp_pci_realize;
 318    k->exit = rp_pci_exit;
 319    k->vendor_id = PCI_VENDOR_ID_XILINX;
 320    k->device_id = 0;
 321    k->revision = 0;
 322    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
 323    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
 324}
 325
 326static const TypeInfo rp_info = {
 327    .name          = TYPE_REMOTE_PORT_PCI_DEVICE,
 328    .parent        = TYPE_PCI_DEVICE,
 329    .instance_size = sizeof(RemotePortPCIDevice),
 330    .instance_init = rp_pci_init,
 331    .class_init    = rp_pci_class_init,
 332    .interfaces    = (InterfaceInfo[]) {
 333        { TYPE_REMOTE_PORT_DEVICE },
 334        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
 335        { },
 336    },
 337};
 338
 339static void rp_register_types(void)
 340{
 341    type_register_static(&rp_info);
 342}
 343
 344type_init(rp_register_types)
 345