Commit 79627472 authored by Luiz Capitulino's avatar Luiz Capitulino
Browse files

qapi: Convert query-pci



This also fixes a bug with the old version: QMP would invert device id
and vendor id. This would look ok on HMP because it was printing
"device:vendor" instead of "vendor:device".

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
Signed-off-by: default avatarLuiz Capitulino <lcapitulino@redhat.com>
parent 96637bcd
Loading
Loading
Loading
Loading
+101 −0
Original line number Diff line number Diff line
@@ -388,6 +388,107 @@ void hmp_info_balloon(Monitor *mon)
    qapi_free_BalloonInfo(info);
}

static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
{
    PciMemoryRegionList *region;

    monitor_printf(mon, "  Bus %2" PRId64 ", ", dev->bus);
    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
                   dev->slot, dev->function);
    monitor_printf(mon, "    ");

    if (dev->class_info.has_desc) {
        monitor_printf(mon, "%s", dev->class_info.desc);
    } else {
        monitor_printf(mon, "Class %04" PRId64, dev->class_info.class);
    }

    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
                   dev->id.vendor, dev->id.device);

    if (dev->has_irq) {
        monitor_printf(mon, "      IRQ %" PRId64 ".\n", dev->irq);
    }

    if (dev->has_pci_bridge) {
        monitor_printf(mon, "      BUS %" PRId64 ".\n",
                       dev->pci_bridge->bus.number);
        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
                       dev->pci_bridge->bus.secondary);
        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
                       dev->pci_bridge->bus.subordinate);

        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
                       dev->pci_bridge->bus.io_range->base,
                       dev->pci_bridge->bus.io_range->limit);

        monitor_printf(mon,
                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
                       dev->pci_bridge->bus.memory_range->base,
                       dev->pci_bridge->bus.memory_range->limit);

        monitor_printf(mon, "      prefetchable memory range "
                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
                       dev->pci_bridge->bus.prefetchable_range->base,
                       dev->pci_bridge->bus.prefetchable_range->limit);
    }

    for (region = dev->regions; region; region = region->next) {
        uint64_t addr, size;

        addr = region->value->address;
        size = region->value->size;

        monitor_printf(mon, "      BAR%" PRId64 ": ", region->value->bar);

        if (!strcmp(region->value->type, "io")) {
            monitor_printf(mon, "I/O at 0x%04" PRIx64
                                " [0x%04" PRIx64 "].\n",
                           addr, addr + size - 1);
        } else {
            monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
                               " [0x%08" PRIx64 "].\n",
                           region->value->mem_type_64 ? 64 : 32,
                           region->value->prefetch ? " prefetchable" : "",
                           addr, addr + size - 1);
        }
    }

    monitor_printf(mon, "      id \"%s\"\n", dev->qdev_id);

    if (dev->has_pci_bridge) {
        if (dev->pci_bridge->has_devices) {
            PciDeviceInfoList *cdev;
            for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
                hmp_info_pci_device(mon, cdev->value);
            }
        }
    }
}

void hmp_info_pci(Monitor *mon)
{
    PciInfoList *info;
    Error *err = NULL;

    info = qmp_query_pci(&err);
    if (err) {
        monitor_printf(mon, "PCI devices not supported\n");
        error_free(err);
        return;
    }

    for (; info; info = info->next) {
        PciDeviceInfoList *dev;

        for (dev = info->value->devices; dev; dev = dev->next) {
            hmp_info_pci_device(mon, dev->value);
        }
    }

    qapi_free_PciInfoList(info);
}

void hmp_quit(Monitor *mon, const QDict *qdict)
{
    monitor_suspend(mon);
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ void hmp_info_blockstats(Monitor *mon);
void hmp_info_vnc(Monitor *mon);
void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_info_pci(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
+6 −9
Original line number Diff line number Diff line
@@ -21,20 +21,17 @@
#include "sysemu.h"
#include "monitor.h"
#include "pci.h"
#include "qmp-commands.h"

static void pci_error_message(Monitor *mon)
PciInfoList *qmp_query_pci(Error **errp)
{
    monitor_printf(mon, "PCI devices not supported\n");
    error_set(errp, QERR_UNSUPPORTED);
    return NULL;
}

void do_pci_info(Monitor *mon, QObject **ret_data)
{
    pci_error_message(mon);
}

void do_pci_info_print(Monitor *mon, const QObject *data)
static void pci_error_message(Monitor *mon)
{
    pci_error_message(mon);
    monitor_printf(mon, "PCI devices not supported\n");
}

int do_pcie_aer_inejct_error(Monitor *mon,
+120 −202
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@
#include "net.h"
#include "sysemu.h"
#include "loader.h"
#include "qemu-objects.h"
#include "range.h"
#include "qmp-commands.h"

//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -1164,276 +1164,194 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
    }
}

static void pci_device_print(Monitor *mon, QDict *device)
static const pci_class_desc *get_class_desc(int class)
{
    QDict *qdict;
    QListEntry *entry;
    uint64_t addr, size;

    monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
                        qdict_get_int(device, "slot"),
                        qdict_get_int(device, "function"));
    monitor_printf(mon, "    ");
    const pci_class_desc *desc;

    qdict = qdict_get_qdict(device, "class_info");
    if (qdict_haskey(qdict, "desc")) {
        monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
    } else {
        monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
    desc = pci_class_descriptions;
    while (desc->desc && class != desc->class) {
        desc++;
    }

    qdict = qdict_get_qdict(device, "id");
    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
                        qdict_get_int(qdict, "device"),
                        qdict_get_int(qdict, "vendor"));

    if (qdict_haskey(device, "irq")) {
        monitor_printf(mon, "      IRQ %" PRId64 ".\n",
                            qdict_get_int(device, "irq"));
    return desc;
}

    if (qdict_haskey(device, "pci_bridge")) {
        QDict *info;

        qdict = qdict_get_qdict(device, "pci_bridge");

        info = qdict_get_qdict(qdict, "bus");
        monitor_printf(mon, "      BUS %" PRId64 ".\n",
                            qdict_get_int(info, "number"));
        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
                            qdict_get_int(info, "secondary"));
        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
                            qdict_get_int(info, "subordinate"));
static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);

        info = qdict_get_qdict(qdict, "io_range");
        monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
                       qdict_get_int(info, "base"),
                       qdict_get_int(info, "limit"));
static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
{
    PciMemoryRegionList *head = NULL, *cur_item = NULL;
    int i;

        info = qdict_get_qdict(qdict, "memory_range");
        monitor_printf(mon,
                       "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
                       qdict_get_int(info, "base"),
                       qdict_get_int(info, "limit"));
    for (i = 0; i < PCI_NUM_REGIONS; i++) {
        const PCIIORegion *r = &dev->io_regions[i];
        PciMemoryRegionList *region;

        info = qdict_get_qdict(qdict, "prefetchable_range");
        monitor_printf(mon, "      prefetchable memory range "
                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
                       qdict_get_int(info, "base"),
        qdict_get_int(info, "limit"));
        if (!r->size) {
            continue;
        }

    QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
        qdict = qobject_to_qdict(qlist_entry_obj(entry));
        monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));

        addr = qdict_get_int(qdict, "address");
        size = qdict_get_int(qdict, "size");
        region = g_malloc0(sizeof(*region));
        region->value = g_malloc0(sizeof(*region->value));

        if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
            monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
                                " [0x%04"FMT_PCIBUS"].\n",
                                addr, addr + size - 1);
        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
            region->value->type = g_strdup("io");
        } else {
            monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
                               " [0x%08"FMT_PCIBUS"].\n",
                                qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
                                qdict_get_bool(qdict, "prefetch") ?
                                " prefetchable" : "", addr, addr + size - 1);
        }
            region->value->type = g_strdup("memory");
            region->value->has_prefetch = true;
            region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
            region->value->has_mem_type_64 = true;
            region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
        }

    monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));
        region->value->bar = i;
        region->value->address = r->addr;
        region->value->size = r->size;

    if (qdict_haskey(device, "pci_bridge")) {
        qdict = qdict_get_qdict(device, "pci_bridge");
        if (qdict_haskey(qdict, "devices")) {
            QListEntry *dev;
            QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
                pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
            }
        }
    }
}

void do_pci_info_print(Monitor *mon, const QObject *data)
{
    QListEntry *bus, *dev;

    QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
        QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
        QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
            pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
        }
    }
}

static QObject *pci_get_dev_class(const PCIDevice *dev)
{
    int class;
    const pci_class_desc *desc;

    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
    desc = pci_class_descriptions;
    while (desc->desc && class != desc->class)
        desc++;

    if (desc->desc) {
        return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
                                  desc->desc, class);
        /* XXX: waiting for the qapi to support GSList */
        if (!cur_item) {
            head = cur_item = region;
        } else {
        return qobject_from_jsonf("{ 'class': %d }", class);
            cur_item->next = region;
            cur_item = region;
        }
    }

static QObject *pci_get_dev_id(const PCIDevice *dev)
{
    return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
                              pci_get_word(dev->config + PCI_VENDOR_ID),
                              pci_get_word(dev->config + PCI_DEVICE_ID));
    return head;
}

static QObject *pci_get_regions_list(const PCIDevice *dev)
static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
                                           int bus_num)
{
    int i;
    QList *regions_list;
    PciBridgeInfo *info;

    regions_list = qlist_new();
    info = g_malloc0(sizeof(*info));

    for (i = 0; i < PCI_NUM_REGIONS; i++) {
        QObject *obj;
        const PCIIORegion *r = &dev->io_regions[i];
    info->bus.number = dev->config[PCI_PRIMARY_BUS];
    info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
    info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];

        if (!r->size) {
            continue;
        }
    info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
    info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
    info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);

        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
                                     "'address': %" PRId64 ", "
                                     "'size': %" PRId64 " }",
                                     i, r->addr, r->size);
        } else {
            int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
    info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
    info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
    info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);

            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
                                     "'mem_type_64': %i, 'prefetch': %i, "
                                     "'address': %" PRId64 ", "
                                     "'size': %" PRId64 " }",
                                     i, mem_type_64,
                                     r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
                                     r->addr, r->size);
        }
    info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
    info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
    info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);

        qlist_append_obj(regions_list, obj);
    if (dev->config[PCI_SECONDARY_BUS] != 0) {
        PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
        if (child_bus) {
            info->has_devices = true;
            info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
        }

    return QOBJECT(regions_list);
    }

static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
    return info;
}

static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
                                           int bus_num)
{
    const pci_class_desc *desc;
    PciDeviceInfo *info;
    uint8_t type;
    QObject *obj;
    int class;

    info = g_malloc0(sizeof(*info));
    info->bus = bus_num;
    info->slot = PCI_SLOT(dev->devfn);
    info->function = PCI_FUNC(dev->devfn);

    obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"
                              " 'qdev_id': %s }",
                              bus_num,
                              PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
                              pci_get_dev_class(dev), pci_get_dev_id(dev),
                              pci_get_regions_list(dev),
                              dev->qdev.id ? dev->qdev.id : "");
    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
    info->class_info.class = class;
    desc = get_class_desc(class);
    if (desc->desc) {
        info->class_info.has_desc = true;
        info->class_info.desc = g_strdup(desc->desc);
    }

    info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
    info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
    info->regions = qmp_query_pci_regions(dev);
    info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");

    if (dev->config[PCI_INTERRUPT_PIN] != 0) {
        QDict *qdict = qobject_to_qdict(obj);
        qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
        info->has_irq = true;
        info->irq = dev->config[PCI_INTERRUPT_LINE];
    }

    type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
    if (type == PCI_HEADER_TYPE_BRIDGE) {
        QDict *qdict;
        QObject *pci_bridge;

        pci_bridge = qobject_from_jsonf("{ 'bus': "
        "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
        "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
        "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
        "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
        dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
        dev->config[PCI_SUBORDINATE_BUS],
        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
                               PCI_BASE_ADDRESS_MEM_PREFETCH),
        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
                                PCI_BASE_ADDRESS_MEM_PREFETCH));

        if (dev->config[PCI_SECONDARY_BUS] != 0) {
            PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);

            if (child_bus) {
                qdict = qobject_to_qdict(pci_bridge);
                qdict_put_obj(qdict, "devices",
                              pci_get_devices_list(child_bus,
                                                   dev->config[PCI_SECONDARY_BUS]));
            }
        }
        qdict = qobject_to_qdict(obj);
        qdict_put_obj(qdict, "pci_bridge", pci_bridge);
        info->has_pci_bridge = true;
        info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
    }

    return obj;
    return info;
}

static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
{
    int devfn;
    PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
    PCIDevice *dev;
    QList *dev_list;

    dev_list = qlist_new();
    int devfn;

    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
        dev = bus->devices[devfn];
        if (dev) {
            qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
            info = g_malloc0(sizeof(*info));
            info->value = qmp_query_pci_device(dev, bus, bus_num);

            /* XXX: waiting for the qapi to support GSList */
            if (!cur_item) {
                head = cur_item = info;
            } else {
                cur_item->next = info;
                cur_item = info;
            }
        }
    }

    return QOBJECT(dev_list);
    return head;
}

static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
{
    PciInfo *info = NULL;

    bus = pci_find_bus(bus, bus_num);
    if (bus) {
        return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
                                  bus_num, pci_get_devices_list(bus, bus_num));
        info = g_malloc0(sizeof(*info));
        info->bus = bus_num;
        info->devices = qmp_query_pci_devices(bus, bus_num);
    }

    return NULL;
    return info;
}

void do_pci_info(Monitor *mon, QObject **ret_data)
PciInfoList *qmp_query_pci(Error **errp)
{
    QList *bus_list;
    PciInfoList *info, *head = NULL, *cur_item = NULL;
    struct PCIHostBus *host;

    bus_list = qlist_new();

    QLIST_FOREACH(host, &host_buses, next) {
        QObject *obj = pci_get_bus_dict(host->bus, 0);
        if (obj) {
            qlist_append_obj(bus_list, obj);
        info = g_malloc0(sizeof(*info));
        info->value = qmp_query_pci_bus(host->bus, 0);

        /* XXX: waiting for the qapi to support GSList */
        if (!cur_item) {
            head = cur_item = info;
        } else {
            cur_item->next = info;
            cur_item = info;
        }
    }

    *ret_data = QOBJECT(bus_list);
    return head;
}

static const char * const pci_nic_models[] = {
+0 −4
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@
#define QEMU_PCI_H

#include "qemu-common.h"
#include "qobject.h"

#include "qdev.h"
#include "memory.h"
@@ -271,9 +270,6 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                     unsigned *slotp);

void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);

void pci_device_deassert_intx(PCIDevice *dev);

static inline void
Loading