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