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    } else {
 124        dev->msix_pba_bar = dev->msix_table_bar;
 125    }
 126    dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
 127
 128    dev->msix_enabled = true;
 129}
 130
 131void qpci_msix_disable(QPCIDevice *dev)
 132{
 133    uint8_t addr;
 134    uint16_t val;
 135
 136    g_assert(dev->msix_enabled);
 137    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 138    g_assert_cmphex(addr, !=, 0);
 139    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 140    qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
 141                                                val & ~PCI_MSIX_FLAGS_ENABLE);
 142
 143    if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) {
 144        qpci_iounmap(dev, dev->msix_pba_bar);
 145    }
 146    qpci_iounmap(dev, dev->msix_table_bar);
 147
 148    dev->msix_enabled = 0;
 149    dev->msix_table_off = 0;
 150    dev->msix_pba_off = 0;
 151}
 152
 153bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
 154{
 155    uint32_t pba_entry;
 156    uint8_t bit_n = entry % 32;
 157    uint64_t  off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
 158
 159    g_assert(dev->msix_enabled);
 160    pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
 161    qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
 162                   pba_entry & ~(1 << bit_n));
 163    return (pba_entry & (1 << bit_n)) != 0;
 164}
 165
 166bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
 167{
 168    uint8_t addr;
 169    uint16_t val;
 170    uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
 171
 172    g_assert(dev->msix_enabled);
 173    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 174    g_assert_cmphex(addr, !=, 0);
 175    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 176
 177    if (val & PCI_MSIX_FLAGS_MASKALL) {
 178        return true;
 179    } else {
 180        return (qpci_io_readl(dev, dev->msix_table_bar,
 181                              vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
 182                & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
 183    }
 184}
 185
 186uint16_t qpci_msix_table_size(QPCIDevice *dev)
 187{
 188    uint8_t addr;
 189    uint16_t control;
 190
 191    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 192    g_assert_cmphex(addr, !=, 0);
 193
 194    control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 195    return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
 196}
 197
 198uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
 199{
 200    return dev->bus->config_readb(dev->bus, dev->devfn, offset);
 201}
 202
 203uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
 204{
 205    return dev->bus->config_readw(dev->bus, dev->devfn, offset);
 206}
 207
 208uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
 209{
 210    return dev->bus->config_readl(dev->bus, dev->devfn, offset);
 211}
 212
 213
 214void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
 215{
 216    dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
 217}
 218
 219void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
 220{
 221    dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
 222}
 223
 224void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
 225{
 226    dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 227}
 228
 229uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
 230{
 231    if (token.addr < QPCI_PIO_LIMIT) {
 232        return dev->bus->pio_readb(dev->bus, token.addr + off);
 233    } else {
 234        uint8_t val;
 235        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 236        return val;
 237    }
 238}
 239
 240uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
 241{
 242    if (token.addr < QPCI_PIO_LIMIT) {
 243        return dev->bus->pio_readw(dev->bus, token.addr + off);
 244    } else {
 245        uint16_t val;
 246        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 247        return le16_to_cpu(val);
 248    }
 249}
 250
 251uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
 252{
 253    if (token.addr < QPCI_PIO_LIMIT) {
 254        return dev->bus->pio_readl(dev->bus, token.addr + off);
 255    } else {
 256        uint32_t val;
 257        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 258        return le32_to_cpu(val);
 259    }
 260}
 261
 262uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
 263{
 264    if (token.addr < QPCI_PIO_LIMIT) {
 265        return dev->bus->pio_readq(dev->bus, token.addr + off);
 266    } else {
 267        uint64_t val;
 268        dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
 269        return le64_to_cpu(val);
 270    }
 271}
 272
 273void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
 274                    uint8_t value)
 275{
 276    if (token.addr < QPCI_PIO_LIMIT) {
 277        dev->bus->pio_writeb(dev->bus, token.addr + off, value);
 278    } else {
 279        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 280    }
 281}
 282
 283void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
 284                    uint16_t value)
 285{
 286    if (token.addr < QPCI_PIO_LIMIT) {
 287        dev->bus->pio_writew(dev->bus, token.addr + off, value);
 288    } else {
 289        value = cpu_to_le16(value);
 290        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 291    }
 292}
 293
 294void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
 295                    uint32_t value)
 296{
 297    if (token.addr < QPCI_PIO_LIMIT) {
 298        dev->bus->pio_writel(dev->bus, token.addr + off, value);
 299    } else {
 300        value = cpu_to_le32(value);
 301        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 302    }
 303}
 304
 305void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
 306                    uint64_t value)
 307{
 308    if (token.addr < QPCI_PIO_LIMIT) {
 309        dev->bus->pio_writeq(dev->bus, token.addr + off, value);
 310    } else {
 311        value = cpu_to_le64(value);
 312        dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
 313    }
 314}
 315
 316void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
 317                  void *buf, size_t len)
 318{
 319    g_assert(token.addr >= QPCI_PIO_LIMIT);
 320    dev->bus->memread(dev->bus, token.addr + off, buf, len);
 321}
 322
 323void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
 324                   const void *buf, size_t len)
 325{
 326    g_assert(token.addr >= QPCI_PIO_LIMIT);
 327    dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
 328}
 329
 330QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
 331{
 332    QPCIBus *bus = dev->bus;
 333    static const int bar_reg_map[] = {
 334        PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
 335        PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
 336    };
 337    QPCIBar bar;
 338    int bar_reg;
 339    uint32_t addr, size;
 340    uint32_t io_type;
 341    uint64_t loc;
 342
 343    g_assert(barno >= 0 && barno <= 5);
 344    bar_reg = bar_reg_map[barno];
 345
 346    qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
 347    addr = qpci_config_readl(dev, bar_reg);
 348
 349    io_type = addr & PCI_BASE_ADDRESS_SPACE;
 350    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 351        addr &= PCI_BASE_ADDRESS_IO_MASK;
 352    } else {
 353        addr &= PCI_BASE_ADDRESS_MEM_MASK;
 354    }
 355
 356    g_assert(addr); /* Must have *some* size bits */
 357
 358    size = 1U << ctz32(addr);
 359    if (sizeptr) {
 360        *sizeptr = size;
 361    }
 362
 363    if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
 364        loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
 365
 366        g_assert(loc >= bus->pio_alloc_ptr);
 367        g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */
 368
 369        bus->pio_alloc_ptr = loc + size;
 370
 371        qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
 372    } else {
 373        loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size);
 374
 375        /* Check for space */
 376        g_assert(loc >= bus->mmio_alloc_ptr);
 377        g_assert(loc + size <= bus->mmio_limit);
 378
 379        bus->mmio_alloc_ptr = loc + size;
 380
 381        qpci_config_writel(dev, bar_reg, loc);
 382    }
 383
 384    bar.addr = loc;
 385    return bar;
 386}
 387
 388void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
 389{
 390    /* FIXME */
 391}
 392
 393QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
 394{
 395    QPCIBar bar = { .addr = addr };
 396    return bar;
 397}
 398
 399void qpci_plug_device_test(const char *driver, const char *id,
 400                           uint8_t slot, const char *opts)
 401{
 402    qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
 403                         opts ? ", " : "", opts ? opts : "");
 404}
 405