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 "libqos/pci.h"
  14
  15#include "hw/pci/pci_regs.h"
  16#include <glib.h>
  17
  18void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
  19                         void (*func)(QPCIDevice *dev, int devfn, void *data),
  20                         void *data)
  21{
  22    int slot;
  23
  24    for (slot = 0; slot < 32; slot++) {
  25        int fn;
  26
  27        for (fn = 0; fn < 8; fn++) {
  28            QPCIDevice *dev;
  29
  30            dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
  31            if (!dev) {
  32                continue;
  33            }
  34
  35            if (vendor_id != -1 &&
  36                qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
  37                continue;
  38            }
  39
  40            if (device_id != -1 &&
  41                qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
  42                continue;
  43            }
  44
  45            func(dev, QPCI_DEVFN(slot, fn), data);
  46        }
  47    }
  48}
  49
  50QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
  51{
  52    QPCIDevice *dev;
  53
  54    dev = g_malloc0(sizeof(*dev));
  55    dev->bus = bus;
  56    dev->devfn = devfn;
  57
  58    if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
  59        g_free(dev);
  60        return NULL;
  61    }
  62
  63    return dev;
  64}
  65
  66void qpci_device_enable(QPCIDevice *dev)
  67{
  68    uint16_t cmd;
  69
  70    /* FIXME -- does this need to be a bus callout? */
  71    cmd = qpci_config_readw(dev, PCI_COMMAND);
  72    cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
  73    qpci_config_writew(dev, PCI_COMMAND, cmd);
  74
  75    /* Verify the bits are now set. */
  76    cmd = qpci_config_readw(dev, PCI_COMMAND);
  77    g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO);
  78    g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY);
  79    g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER);
  80}
  81
  82uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id)
  83{
  84    uint8_t cap;
  85    uint8_t addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
  86
  87    do {
  88        cap = qpci_config_readb(dev, addr);
  89        if (cap != id) {
  90            addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
  91        }
  92    } while (cap != id && addr != 0);
  93
  94    return addr;
  95}
  96
  97void qpci_msix_enable(QPCIDevice *dev)
  98{
  99    uint8_t addr;
 100    uint16_t val;
 101    uint32_t table;
 102    uint8_t bir_table;
 103    uint8_t bir_pba;
 104    void *offset;
 105
 106    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 107    g_assert_cmphex(addr, !=, 0);
 108
 109    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 110    qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
 111
 112    table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
 113    bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
 114    offset = qpci_iomap(dev, bir_table, NULL);
 115    dev->msix_table = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
 116
 117    table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
 118    bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
 119    if (bir_pba != bir_table) {
 120        offset = qpci_iomap(dev, bir_pba, NULL);
 121    }
 122    dev->msix_pba = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
 123
 124    g_assert(dev->msix_table != NULL);
 125    g_assert(dev->msix_pba != NULL);
 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);
 142    qpci_iounmap(dev, dev->msix_pba);
 143    dev->msix_enabled = 0;
 144    dev->msix_table = NULL;
 145    dev->msix_pba = NULL;
 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    void *addr = dev->msix_pba + (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
 153
 154    g_assert(dev->msix_enabled);
 155    pba_entry = qpci_io_readl(dev, addr);
 156    qpci_io_writel(dev, addr, pba_entry & ~(1 << bit_n));
 157    return (pba_entry & (1 << bit_n)) != 0;
 158}
 159
 160bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
 161{
 162    uint8_t addr;
 163    uint16_t val;
 164    void *vector_addr = dev->msix_table + (entry * PCI_MSIX_ENTRY_SIZE);
 165
 166    g_assert(dev->msix_enabled);
 167    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 168    g_assert_cmphex(addr, !=, 0);
 169    val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 170
 171    if (val & PCI_MSIX_FLAGS_MASKALL) {
 172        return true;
 173    } else {
 174        return (qpci_io_readl(dev, vector_addr + PCI_MSIX_ENTRY_VECTOR_CTRL)
 175                                            & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
 176    }
 177}
 178
 179uint16_t qpci_msix_table_size(QPCIDevice *dev)
 180{
 181    uint8_t addr;
 182    uint16_t control;
 183
 184    addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
 185    g_assert_cmphex(addr, !=, 0);
 186
 187    control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
 188    return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
 189}
 190
 191uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
 192{
 193    return dev->bus->config_readb(dev->bus, dev->devfn, offset);
 194}
 195
 196uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
 197{
 198    return dev->bus->config_readw(dev->bus, dev->devfn, offset);
 199}
 200
 201uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
 202{
 203    return dev->bus->config_readl(dev->bus, dev->devfn, offset);
 204}
 205
 206
 207void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
 208{
 209    dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
 210}
 211
 212void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
 213{
 214    dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
 215}
 216
 217void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
 218{
 219    dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 220}
 221
 222
 223uint8_t qpci_io_readb(QPCIDevice *dev, void *data)
 224{
 225    return dev->bus->io_readb(dev->bus, data);
 226}
 227
 228uint16_t qpci_io_readw(QPCIDevice *dev, void *data)
 229{
 230    return dev->bus->io_readw(dev->bus, data);
 231}
 232
 233uint32_t qpci_io_readl(QPCIDevice *dev, void *data)
 234{
 235    return dev->bus->io_readl(dev->bus, data);
 236}
 237
 238
 239void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value)
 240{
 241    dev->bus->io_writeb(dev->bus, data, value);
 242}
 243
 244void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value)
 245{
 246    dev->bus->io_writew(dev->bus, data, value);
 247}
 248
 249void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value)
 250{
 251    dev->bus->io_writel(dev->bus, data, value);
 252}
 253
 254void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
 255{
 256    return dev->bus->iomap(dev->bus, dev, barno, sizeptr);
 257}
 258
 259void qpci_iounmap(QPCIDevice *dev, void *data)
 260{
 261    dev->bus->iounmap(dev->bus, data);
 262}
 263
 264
 265