qemu/tests/libqos/pci.c
<<
>>
Prefs
   1/*
   2 * libqos PCI bindings
   3 *
   4 * Copyright IBM, Corp. 2012-2013
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "libqos/pci.h"
  15
  16#include "hw/pci/pci_regs.h"
  17#include "qemu/host-utils.h"
  18
  19void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
  20                         void (*func)(QPCIDevice *dev, int devfn, void *data),
  21                         void *data)
  22{
  23    int slot;
  24
  25    for (slot = 0; slot < 32; slot++) {
  26        int fn;
  27
  28        for (fn = 0; fn < 8; fn++) {
  29            QPCIDevice *dev;
  30
  31            dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
  32            if (!dev) {
  33                continue;
  34            }
  35
  36            if (vendor_id != -1 &&
  37                qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
  38                g_free(dev);
  39                continue;
  40            }
  41
  42            if (device_id != -1 &&
  43                qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
  44                g_free(dev);
  45                continue;
  46            }
  47
  48            func(dev, QPCI_DEVFN(slot, fn), data);
  49        }
  50    }
  51}
  52
  53QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
  54{
  55    QPCIDevice *dev;
  56
  57    dev = g_malloc0(sizeof(*dev));
  58    dev->bus = bus;
  59    dev->devfn = devfn;
  60
  61    if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
  62        g_free(dev);
  63        return NULL;
  64    }
  65
  66    return dev;
  67}
  68
  69void qpci_device_enable(QPCIDevice *dev)
  70{
  71    uint16_t cmd;
  72
  73    /* FIXME -- does this need to be a bus callout? */
  74    cmd = qpci_config_readw(dev, PCI_COMMAND);
  75    cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
  76    qpci_config_writew(dev, PCI_COMMAND, cmd);
  77
  78    /* Verify the bits are now set. */
  79    cmd = qpci_config_readw(dev, PCI_COMMAND);
  80    g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO);
  81    g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY);
  82    g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER);
  83}
  84
  85uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id)
  86{
  87    uint8_t cap;
  88    uint8_t addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
  89
  90    do {
  91        cap = qpci_config_readb(dev, addr);
  92        if (cap != id) {
  93            addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
  94        }
  95    } while (cap != id && addr != 0);
  96
  97    return addr;
  98}
  99
 100void qpci_msix_enable(QPCIDevice *dev)
 101{
 102    uint8_t addr;
 103    uint16_t val;
 104    uint32_t table;
 105    uint8_t bir_table;
 106    uint8_t bir_pba;
 107
 108    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 109    g_assert_cmphex(addr, !=, 0);
 110
 111    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 112    qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
 113
 114    table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
 115    bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
 116    dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL);
 117    dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
 118
 119    table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
 120    bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
 121    if (bir_pba != bir_table) {
 122        dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
 123    }
 124    dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
 125
 126    dev->msix_enabled = true;
 127}
 128
 129void qpci_msix_disable(QPCIDevice *dev)
 130{
 131    uint8_t addr;
 132    uint16_t val;
 133
 134    g_assert(dev->msix_enabled);
 135    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 136    g_assert_cmphex(addr, !=, 0);
 137    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 138    qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
 139                                                val & ~PCI_MSIX_FLAGS_ENABLE);
 140
 141    qpci_iounmap(dev, dev->msix_table_bar);
 142    qpci_iounmap(dev, dev->msix_pba_bar);
 143    dev->msix_enabled = 0;
 144    dev->msix_table_off = 0;
 145    dev->msix_pba_off = 0;
 146}
 147
 148bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
 149{
 150    uint32_t pba_entry;
 151    uint8_t bit_n = entry % 32;
 152    uint64_t  off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
 153
 154    g_assert(dev->msix_enabled);
 155    pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
 156    qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
 157                   pba_entry & ~(1 << bit_n));
 158    return (pba_entry & (1 << bit_n)) != 0;
 159}
 160
 161bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
 162{
 163    uint8_t addr;
 164    uint16_t val;
 165    uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
 166
 167    g_assert(dev->msix_enabled);
 168    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 169    g_assert_cmphex(addr, !=, 0);
 170    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 171
 172    if (val & PCI_MSIX_FLAGS_MASKALL) {
 173        return true;
 174    } else {
 175        return (qpci_io_readl(dev, dev->msix_table_bar,
 176                              vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
 177                & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
 178    }
 179}
 180
 181uint16_t qpci_msix_table_size(QPCIDevice *dev)
 182{
 183    uint8_t addr;
 184    uint16_t control;
 185
 186    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 187    g_assert_cmphex(addr, !=, 0);
 188
 189    control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 190    return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
 191}
 192
 193uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
 194{
 195    return dev->bus->config_readb(dev->bus, dev->devfn, offset);
 196}
 197
 198uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
 199{
 200    return dev->bus->config_readw(dev->bus, dev->devfn, offset);
 201}
 202
 203uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
 204{
 205    return dev->bus->config_readl(dev->bus, dev->devfn, offset);
 206}
 207
 208
 209void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
 210{
 211    dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
 212}
 213
 214void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
 215{
 216    dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
 217}
 218
 219void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
 220{
 221    dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 222}
 223
 224uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
 225{
 226    if (token.addr < QPCI_PIO_LIMIT) {
 227        return dev->bus->pio_readb(dev->bus, token.addr + off);
 228    } else {
 229        uint8_t val;
 230        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 231        return val;
 232    }
 233}
 234
 235uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
 236{
 237    if (token.addr < QPCI_PIO_LIMIT) {
 238        return dev->bus->pio_readw(dev->bus, token.addr + off);
 239    } else {
 240        uint16_t val;
 241        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 242        return le16_to_cpu(val);
 243    }
 244}
 245
 246uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
 247{
 248    if (token.addr < QPCI_PIO_LIMIT) {
 249        return dev->bus->pio_readl(dev->bus, token.addr + off);
 250    } else {
 251        uint32_t val;
 252        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 253        return le32_to_cpu(val);
 254    }
 255}
 256
 257uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
 258{
 259    if (token.addr < QPCI_PIO_LIMIT) {
 260        return dev->bus->pio_readq(dev->bus, token.addr + off);
 261    } else {
 262        uint64_t val;
 263        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 264        return le64_to_cpu(val);
 265    }
 266}
 267
 268void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
 269                    uint8_t value)
 270{
 271    if (token.addr < QPCI_PIO_LIMIT) {
 272        dev->bus->pio_writeb(dev->bus, token.addr + off, value);
 273    } else {
 274        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 275    }
 276}
 277
 278void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
 279                    uint16_t value)
 280{
 281    if (token.addr < QPCI_PIO_LIMIT) {
 282        dev->bus->pio_writew(dev->bus, token.addr + off, value);
 283    } else {
 284        value = cpu_to_le16(value);
 285        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 286    }
 287}
 288
 289void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
 290                    uint32_t value)
 291{
 292    if (token.addr < QPCI_PIO_LIMIT) {
 293        dev->bus->pio_writel(dev->bus, token.addr + off, value);
 294    } else {
 295        value = cpu_to_le32(value);
 296        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 297    }
 298}
 299
 300void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
 301                    uint64_t value)
 302{
 303    if (token.addr < QPCI_PIO_LIMIT) {
 304        dev->bus->pio_writeq(dev->bus, token.addr + off, value);
 305    } else {
 306        value = cpu_to_le64(value);
 307        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 308    }
 309}
 310
 311void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
 312                  void *buf, size_t len)
 313{
 314    g_assert(token.addr >= QPCI_PIO_LIMIT);
 315    dev->bus->memread(dev->bus, token.addr + off, buf, len);
 316}
 317
 318void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
 319                   const void *buf, size_t len)
 320{
 321    g_assert(token.addr >= QPCI_PIO_LIMIT);
 322    dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
 323}
 324
 325QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
 326{
 327    QPCIBus *bus = dev->bus;
 328    static const int bar_reg_map[] = {
 329        PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
 330        PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
 331    };
 332    QPCIBar bar;
 333    int bar_reg;
 334    uint32_t addr, size;
 335    uint32_t io_type;
 336    uint64_t loc;
 337
 338    g_assert(barno >= 0 && barno <= 5);
 339    bar_reg = bar_reg_map[barno];
 340
 341    qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
 342    addr = qpci_config_readl(dev, bar_reg);
 343
 344    io_type = addr & PCI_BASE_ADDRESS_SPACE;
 345    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 346        addr &= PCI_BASE_ADDRESS_IO_MASK;
 347    } else {
 348        addr &= PCI_BASE_ADDRESS_MEM_MASK;
 349    }
 350
 351    g_assert(addr); /* Must have *some* size bits */
 352
 353    size = 1U << ctz32(addr);
 354    if (sizeptr) {
 355        *sizeptr = size;
 356    }
 357
 358    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 359        loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
 360
 361        g_assert(loc >= bus->pio_alloc_ptr);
 362        g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */
 363
 364        bus->pio_alloc_ptr = loc + size;
 365
 366        qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
 367    } else {
 368        loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size);
 369
 370        /* Check for space */
 371        g_assert(loc >= bus->mmio_alloc_ptr);
 372        g_assert(loc + size <= bus->mmio_limit);
 373
 374        bus->mmio_alloc_ptr = loc + size;
 375
 376        qpci_config_writel(dev, bar_reg, loc);
 377    }
 378
 379    bar.addr = loc;
 380    return bar;
 381}
 382
 383void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
 384{
 385    /* FIXME */
 386}
 387
 388QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
 389{
 390    QPCIBar bar = { .addr = addr };
 391    return bar;
 392}
 393
 394void qpci_plug_device_test(const char *driver, const char *id,
 395                           uint8_t slot, const char *opts)
 396{
 397    QDict *response;
 398    char *cmd;
 399
 400    cmd = g_strdup_printf("{'execute': 'device_add',"
 401                          " 'arguments': {"
 402                          "   'driver': '%s',"
 403                          "   'addr': '%d',"
 404                          "   %s%s"
 405                          "   'id': '%s'"
 406                          "}}", driver, slot,
 407                          opts ? opts : "", opts ? "," : "",
 408                          id);
 409    response = qmp(cmd);
 410    g_free(cmd);
 411    g_assert(response);
 412    g_assert(!qdict_haskey(response, "error"));
 413    QDECREF(response);
 414}
 415