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: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
parent
96637bcdf9
commit
79627472db
101
hmp.c
101
hmp.c
@ -388,6 +388,107 @@ void hmp_info_balloon(Monitor *mon)
|
|||||||
qapi_free_BalloonInfo(info);
|
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)
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
monitor_suspend(mon);
|
monitor_suspend(mon);
|
||||||
|
1
hmp.h
1
hmp.h
@ -31,6 +31,7 @@ void hmp_info_blockstats(Monitor *mon);
|
|||||||
void hmp_info_vnc(Monitor *mon);
|
void hmp_info_vnc(Monitor *mon);
|
||||||
void hmp_info_spice(Monitor *mon);
|
void hmp_info_spice(Monitor *mon);
|
||||||
void hmp_info_balloon(Monitor *mon);
|
void hmp_info_balloon(Monitor *mon);
|
||||||
|
void hmp_info_pci(Monitor *mon);
|
||||||
void hmp_quit(Monitor *mon, const QDict *qdict);
|
void hmp_quit(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_stop(Monitor *mon, const QDict *qdict);
|
void hmp_stop(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_system_reset(Monitor *mon, const QDict *qdict);
|
void hmp_system_reset(Monitor *mon, const QDict *qdict);
|
||||||
|
@ -21,22 +21,19 @@
|
|||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
#include "qmp-commands.h"
|
||||||
|
|
||||||
|
PciInfoList *qmp_query_pci(Error **errp)
|
||||||
|
{
|
||||||
|
error_set(errp, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void pci_error_message(Monitor *mon)
|
static void pci_error_message(Monitor *mon)
|
||||||
{
|
{
|
||||||
monitor_printf(mon, "PCI devices not supported\n");
|
monitor_printf(mon, "PCI devices not supported\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_pci_info(Monitor *mon, QObject **ret_data)
|
|
||||||
{
|
|
||||||
pci_error_message(mon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_pci_info_print(Monitor *mon, const QObject *data)
|
|
||||||
{
|
|
||||||
pci_error_message(mon);
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_pcie_aer_inejct_error(Monitor *mon,
|
int do_pcie_aer_inejct_error(Monitor *mon,
|
||||||
const QDict *qdict, QObject **ret_data)
|
const QDict *qdict, QObject **ret_data)
|
||||||
{
|
{
|
||||||
|
332
hw/pci.c
332
hw/pci.c
@ -29,8 +29,8 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "qemu-objects.h"
|
|
||||||
#include "range.h"
|
#include "range.h"
|
||||||
|
#include "qmp-commands.h"
|
||||||
|
|
||||||
//#define DEBUG_PCI
|
//#define DEBUG_PCI
|
||||||
#ifdef 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, " ");
|
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
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);
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor_printf(mon, " id \"%s\"\n", qdict_get_str(device, "qdev_id"));
|
|
||||||
|
|
||||||
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;
|
const pci_class_desc *desc;
|
||||||
|
|
||||||
class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
|
|
||||||
desc = pci_class_descriptions;
|
desc = pci_class_descriptions;
|
||||||
while (desc->desc && class != desc->class)
|
while (desc->desc && class != desc->class) {
|
||||||
desc++;
|
desc++;
|
||||||
|
|
||||||
if (desc->desc) {
|
|
||||||
return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
|
|
||||||
desc->desc, class);
|
|
||||||
} else {
|
|
||||||
return qobject_from_jsonf("{ 'class': %d }", class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QObject *pci_get_dev_id(const PCIDevice *dev)
|
static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
|
||||||
{
|
|
||||||
return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
|
|
||||||
pci_get_word(dev->config + PCI_VENDOR_ID),
|
|
||||||
pci_get_word(dev->config + PCI_DEVICE_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
static QObject *pci_get_regions_list(const PCIDevice *dev)
|
static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
|
||||||
{
|
{
|
||||||
|
PciMemoryRegionList *head = NULL, *cur_item = NULL;
|
||||||
int i;
|
int i;
|
||||||
QList *regions_list;
|
|
||||||
|
|
||||||
regions_list = qlist_new();
|
|
||||||
|
|
||||||
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||||
QObject *obj;
|
|
||||||
const PCIIORegion *r = &dev->io_regions[i];
|
const PCIIORegion *r = &dev->io_regions[i];
|
||||||
|
PciMemoryRegionList *region;
|
||||||
|
|
||||||
if (!r->size) {
|
if (!r->size) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
region = g_malloc0(sizeof(*region));
|
||||||
|
region->value = g_malloc0(sizeof(*region->value));
|
||||||
|
|
||||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||||
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
|
region->value->type = g_strdup("io");
|
||||||
"'address': %" PRId64 ", "
|
|
||||||
"'size': %" PRId64 " }",
|
|
||||||
i, r->addr, r->size);
|
|
||||||
} else {
|
} else {
|
||||||
int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
|
region->value->type = g_strdup("memory");
|
||||||
|
region->value->has_prefetch = true;
|
||||||
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
|
region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||||
"'mem_type_64': %i, 'prefetch': %i, "
|
region->value->has_mem_type_64 = true;
|
||||||
"'address': %" PRId64 ", "
|
region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
|
||||||
"'size': %" PRId64 " }",
|
|
||||||
i, mem_type_64,
|
|
||||||
r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
|
|
||||||
r->addr, r->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qlist_append_obj(regions_list, obj);
|
region->value->bar = i;
|
||||||
|
region->value->address = r->addr;
|
||||||
|
region->value->size = r->size;
|
||||||
|
|
||||||
|
/* XXX: waiting for the qapi to support GSList */
|
||||||
|
if (!cur_item) {
|
||||||
|
head = cur_item = region;
|
||||||
|
} else {
|
||||||
|
cur_item->next = region;
|
||||||
|
cur_item = region;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QOBJECT(regions_list);
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
|
static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
|
||||||
|
int bus_num)
|
||||||
static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
|
|
||||||
{
|
{
|
||||||
uint8_t type;
|
PciBridgeInfo *info;
|
||||||
QObject *obj;
|
|
||||||
|
|
||||||
obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p,"
|
info = g_malloc0(sizeof(*info));
|
||||||
" 'qdev_id': %s }",
|
|
||||||
bus_num,
|
info->bus.number = dev->config[PCI_PRIMARY_BUS];
|
||||||
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
|
info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
|
||||||
pci_get_dev_class(dev), pci_get_dev_id(dev),
|
info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
||||||
pci_get_regions_list(dev),
|
|
||||||
dev->qdev.id ? dev->qdev.id : "");
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
|
||||||
|
int bus_num)
|
||||||
|
{
|
||||||
|
const pci_class_desc *desc;
|
||||||
|
PciDeviceInfo *info;
|
||||||
|
uint8_t type;
|
||||||
|
int class;
|
||||||
|
|
||||||
|
info = g_malloc0(sizeof(*info));
|
||||||
|
info->bus = bus_num;
|
||||||
|
info->slot = PCI_SLOT(dev->devfn);
|
||||||
|
info->function = PCI_FUNC(dev->devfn);
|
||||||
|
|
||||||
|
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) {
|
if (dev->config[PCI_INTERRUPT_PIN] != 0) {
|
||||||
QDict *qdict = qobject_to_qdict(obj);
|
info->has_irq = true;
|
||||||
qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
|
info->irq = dev->config[PCI_INTERRUPT_LINE];
|
||||||
}
|
}
|
||||||
|
|
||||||
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||||
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
||||||
QDict *qdict;
|
info->has_pci_bridge = true;
|
||||||
QObject *pci_bridge;
|
info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
PCIDevice *dev;
|
||||||
QList *dev_list;
|
int devfn;
|
||||||
|
|
||||||
dev_list = qlist_new();
|
|
||||||
|
|
||||||
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
|
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
|
||||||
dev = bus->devices[devfn];
|
dev = bus->devices[devfn];
|
||||||
if (dev) {
|
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);
|
bus = pci_find_bus(bus, bus_num);
|
||||||
if (bus) {
|
if (bus) {
|
||||||
return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
|
info = g_malloc0(sizeof(*info));
|
||||||
bus_num, pci_get_devices_list(bus, bus_num));
|
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;
|
struct PCIHostBus *host;
|
||||||
|
|
||||||
bus_list = qlist_new();
|
|
||||||
|
|
||||||
QLIST_FOREACH(host, &host_buses, next) {
|
QLIST_FOREACH(host, &host_buses, next) {
|
||||||
QObject *obj = pci_get_bus_dict(host->bus, 0);
|
info = g_malloc0(sizeof(*info));
|
||||||
if (obj) {
|
info->value = qmp_query_pci_bus(host->bus, 0);
|
||||||
qlist_append_obj(bus_list, obj);
|
|
||||||
|
/* 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[] = {
|
static const char * const pci_nic_models[] = {
|
||||||
|
4
hw/pci.h
4
hw/pci.h
@ -2,7 +2,6 @@
|
|||||||
#define QEMU_PCI_H
|
#define QEMU_PCI_H
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qobject.h"
|
|
||||||
|
|
||||||
#include "qdev.h"
|
#include "qdev.h"
|
||||||
#include "memory.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,
|
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
|
||||||
unsigned *slotp);
|
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);
|
void pci_device_deassert_intx(PCIDevice *dev);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
11
monitor.c
11
monitor.c
@ -2738,8 +2738,7 @@ static const mon_cmd_t info_cmds[] = {
|
|||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show PCI info",
|
.help = "show PCI info",
|
||||||
.user_print = do_pci_info_print,
|
.mhandler.info = hmp_info_pci,
|
||||||
.mhandler.info_new = do_pci_info,
|
|
||||||
},
|
},
|
||||||
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
|
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
|
||||||
defined(TARGET_PPC)
|
defined(TARGET_PPC)
|
||||||
@ -2954,14 +2953,6 @@ static const mon_cmd_t qmp_cmds[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const mon_cmd_t qmp_query_cmds[] = {
|
static const mon_cmd_t qmp_query_cmds[] = {
|
||||||
{
|
|
||||||
.name = "pci",
|
|
||||||
.args_type = "",
|
|
||||||
.params = "",
|
|
||||||
.help = "show PCI info",
|
|
||||||
.user_print = do_pci_info_print,
|
|
||||||
.mhandler.info_new = do_pci_info,
|
|
||||||
},
|
|
||||||
{ /* NULL */ },
|
{ /* NULL */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
128
qapi-schema.json
128
qapi-schema.json
@ -702,6 +702,134 @@
|
|||||||
##
|
##
|
||||||
{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
|
{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @PciMemoryRange:
|
||||||
|
#
|
||||||
|
# A PCI device memory region
|
||||||
|
#
|
||||||
|
# @base: the starting address (guest physical)
|
||||||
|
#
|
||||||
|
# @limit: the ending address (guest physical)
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @PciMemoryRegion
|
||||||
|
#
|
||||||
|
# Information about a PCI device I/O region.
|
||||||
|
#
|
||||||
|
# @bar: the index of the Base Address Register for this region
|
||||||
|
#
|
||||||
|
# @type: 'io' if the region is a PIO region
|
||||||
|
# 'memory' if the region is a MMIO region
|
||||||
|
#
|
||||||
|
# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
|
||||||
|
#
|
||||||
|
# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'type': 'PciMemoryRegion',
|
||||||
|
'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
|
||||||
|
'*prefetch': 'bool', '*mem_type_64': 'bool' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @PciBridgeInfo:
|
||||||
|
#
|
||||||
|
# Information about a PCI Bridge device
|
||||||
|
#
|
||||||
|
# @bus.number: primary bus interface number. This should be the number of the
|
||||||
|
# bus the device resides on.
|
||||||
|
#
|
||||||
|
# @bus.secondary: secondary bus interface number. This is the number of the
|
||||||
|
# main bus for the bridge
|
||||||
|
#
|
||||||
|
# @bus.subordinate: This is the highest number bus that resides below the
|
||||||
|
# bridge.
|
||||||
|
#
|
||||||
|
# @bus.io_range: The PIO range for all devices on this bridge
|
||||||
|
#
|
||||||
|
# @bus.memory_range: The MMIO range for all devices on this bridge
|
||||||
|
#
|
||||||
|
# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
|
||||||
|
# this bridge
|
||||||
|
#
|
||||||
|
# @devices: a list of @PciDeviceInfo for each device on this bridge
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'type': 'PciBridgeInfo',
|
||||||
|
'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
|
||||||
|
'io_range': 'PciMemoryRange',
|
||||||
|
'memory_range': 'PciMemoryRange',
|
||||||
|
'prefetchable_range': 'PciMemoryRange' },
|
||||||
|
'*devices': ['PciDeviceInfo']} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @PciDeviceInfo:
|
||||||
|
#
|
||||||
|
# Information about a PCI device
|
||||||
|
#
|
||||||
|
# @bus: the bus number of the device
|
||||||
|
#
|
||||||
|
# @slot: the slot the device is located in
|
||||||
|
#
|
||||||
|
# @function: the function of the slot used by the device
|
||||||
|
#
|
||||||
|
# @class_info.desc: #optional a string description of the device's class
|
||||||
|
#
|
||||||
|
# @class_info.class: the class code of the device
|
||||||
|
#
|
||||||
|
# @id.device: the PCI device id
|
||||||
|
#
|
||||||
|
# @id.vendor: the PCI vendor id
|
||||||
|
#
|
||||||
|
# @irq: #optional if an IRQ is assigned to the device, the IRQ number
|
||||||
|
#
|
||||||
|
# @qdev_id: the device name of the PCI device
|
||||||
|
#
|
||||||
|
# @pci_bridge: if the device is a PCI bridge, the bridge information
|
||||||
|
#
|
||||||
|
# @regions: a list of the PCI I/O regions associated with the device
|
||||||
|
#
|
||||||
|
# Notes: the contents of @class_info.desc are not stable and should only be
|
||||||
|
# treated as informational.
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'type': 'PciDeviceInfo',
|
||||||
|
'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
|
||||||
|
'class_info': {'*desc': 'str', 'class': 'int'},
|
||||||
|
'id': {'device': 'int', 'vendor': 'int'},
|
||||||
|
'*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
|
||||||
|
'regions': ['PciMemoryRegion']} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @PciInfo:
|
||||||
|
#
|
||||||
|
# Information about a PCI bus
|
||||||
|
#
|
||||||
|
# @bus: the bus index
|
||||||
|
#
|
||||||
|
# @devices: a list of devices on this bus
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @query-pci:
|
||||||
|
#
|
||||||
|
# Return information about the PCI bus topology of the guest.
|
||||||
|
#
|
||||||
|
# Returns: a list of @PciInfo for each PCI bus
|
||||||
|
#
|
||||||
|
# Since: 0.14.0
|
||||||
|
##
|
||||||
|
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @quit:
|
# @quit:
|
||||||
#
|
#
|
||||||
|
@ -1576,6 +1576,12 @@ Note: This example has been shortened as the real response is too long.
|
|||||||
|
|
||||||
EQMP
|
EQMP
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "query-pci",
|
||||||
|
.args_type = "",
|
||||||
|
.mhandler.cmd_new = qmp_marshal_input_query_pci,
|
||||||
|
},
|
||||||
|
|
||||||
SQMP
|
SQMP
|
||||||
query-kvm
|
query-kvm
|
||||||
---------
|
---------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user