[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/5] PCI: Convert pci_info() to QObject
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH 3/5] PCI: Convert pci_info() to QObject |
Date: |
Mon, 18 Jan 2010 18:16:21 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) |
Luiz Capitulino <address@hidden> writes:
> The returned QObject is a QList of all buses. Each bus is
> represented by a QDict, which has a key with a QList of all
> PCI devices attached to it. Each device is represented by
> a QDict.
>
> IMPORTANT: support for printing PCI bridge information and
> its devices is NOT part of this commit, it's going to be
> added by next commits.
>
> Finally, as has happended to other complex conversions,
> it's hard to split this commit as part of it are new
> functions which are called by each other.
>
> Signed-off-by: Luiz Capitulino <address@hidden>
Looks pretty good. A few remarks follow inline.
> ---
> hw/pci.c | 308
> +++++++++++++++++++++++++++++++++++++++++++++----------------
> hw/pci.h | 4 +-
> monitor.c | 3 +-
> 3 files changed, 234 insertions(+), 81 deletions(-)
>
> diff --git a/hw/pci.c b/hw/pci.c
> index 08e51f8..8275ceb 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -27,6 +27,7 @@
> #include "net.h"
> #include "sysemu.h"
> #include "loader.h"
> +#include "qemu-objects.h"
>
> //#define DEBUG_PCI
> #ifdef DEBUG_PCI
> @@ -1075,119 +1076,268 @@ static const pci_class_desc
> pci_class_descriptions[] =
> { 0, NULL}
> };
>
> -static void pci_info_device(PCIBus *bus, PCIDevice *d)
> +static void pci_for_each_device_under_bus(PCIBus *bus,
> + void (*fn)(PCIBus *b, PCIDevice
> *d))
> {
> - Monitor *mon = cur_mon;
> - int i, class;
> - PCIIORegion *r;
> - const pci_class_desc *desc;
> + PCIDevice *d;
> + int devfn;
>
> - monitor_printf(mon, " Bus %2d, device %3d, function %d:\n",
> - pci_bus_num(d->bus),
> - PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
> - class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> + d = bus->devices[devfn];
> + if (d) {
> + fn(bus, d);
> + }
> + }
> +}
> +
> +void pci_for_each_device(PCIBus *bus, int bus_num,
> + void (*fn)(PCIBus *b, PCIDevice *d))
> +{
> + bus = pci_find_bus(bus, bus_num);
> +
> + if (bus) {
> + pci_for_each_device_under_bus(bus, fn);
> + }
> +}
> +
> +static void pci_device_print(Monitor *mon, QDict *device)
> +{
> + 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"));
> + }
> +
> + /* TODO: PCI bridge info */
> +
> + 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"));
> +
> + /* TODO: PCI bridge devices */
> +}
> +
> +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 char *str = "";
> + 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) {
[...]
> + str = desc->desc;
> + }
> +
> + return qobject_from_jsonf("{ 'desc': %s, 'class': %d }", str, class);
> +}
This yields 'desc': '' for unknown class. I find that a bit unnatural.
If we don't have a desc, put none into the dictionary.
> +
> +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));
> +}
> +
> +static QObject *pci_get_regions_list(const PCIDevice *dev)
> +{
> + int i;
> + QList *regions_list;
> +
> + regions_list = qlist_new();
> +
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + const PCIIORegion *r = &dev->io_regions[i];
> if (r->size != 0) {
You're struggling with long lines in this function. "if (!r->size)
continue" avoids nesting. Matter of taste, of course.
> - monitor_printf(mon, " BAR%d: ", i);
> + QObject *obj;
> if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
> - monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
> - " [0x%04"FMT_PCIBUS"].\n",
> - r->addr, r->addr + r->size - 1);
> + obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
> + "'address': %" PRId64 ", "
> + "'size': %" PRId64 " }",
> + i, r->addr, r->size);
> } else {
> - const char *type = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64 ?
> - "64 bit" : "32 bit";
> - const char *prefetch =
> - r->type & PCI_BASE_ADDRESS_MEM_PREFETCH ?
> - " prefetchable" : "";
> -
> - monitor_printf(mon, "%s%s memory at 0x%08"FMT_PCIBUS
> - " [0x%08"FMT_PCIBUS"].\n",
> - type, prefetch,
> - r->addr, r->addr + r->size - 1);
> + int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
> +
> + 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);
> }
> + qlist_append_obj(regions_list, obj);
> }
> }
> - monitor_printf(mon, " id \"%s\"\n", d->qdev.id ? d->qdev.id : "");
> - if (class == 0x0604 && d->config[0x19] != 0) {
> - pci_for_each_device(bus, d->config[0x19], pci_info_device);
> +
> + return QOBJECT(regions_list);
> +}
> +
> +static QObject *pci_get_dev_dict(const PCIDevice *dev, int bus_num)
> +{
> + QObject *obj;
> +
> + 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 : "");
Why repeat the bus number? See below.
> +
> + 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]));
> }
> +
> + return obj;
> }
>
> -static void pci_for_each_device_under_bus(PCIBus *bus,
> - void (*fn)(PCIBus *b, PCIDevice
> *d))
> +static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
> {
> - PCIDevice *d;
> int devfn;
> + PCIDevice *dev;
> + QList *dev_list;
>
> - for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> - d = bus->devices[devfn];
> - if (d)
> - fn(bus, d);
> + dev_list = qlist_new();
> +
> + 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_num));
> + }
> }
> +
> + return QOBJECT(dev_list);
> }
>
> -void pci_for_each_device(PCIBus *bus, int bus_num,
> - void (*fn)(PCIBus *b, PCIDevice *d))
> +static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
> {
> bus = pci_find_bus(bus, bus_num);
> -
> if (bus) {
> - pci_for_each_device_under_bus(bus, fn);
> + return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
> + bus_num, pci_get_devices_list(bus,
> bus_num));
> }
> +
> + return NULL;
> }
>
> -void pci_info(Monitor *mon)
> +/**
> + * do_pci_info(): PCI buses and devices information
> + *
> + * The returned QObject is a QList of all buses. Each bus is
> + * represented by a QDict, which has a key with a QList of all
> + * PCI devices attached to it. Each device is represented by
> + * a QDict.
> + *
> + * The bus QDict contains the following:
> + *
> + * - "bus": bus number
> + * - "devices": a QList of QDicts, each QDict represents a PCI
> + * device
> + *
> + * The PCI device QDict contains the following:
> + *
> + * - "bus": bus number
This is redundant, because a device QDict is always contained in a bus
QDict, which has the bus number.
> + * - "slot": slot number
> + * - "function": function number
> + * - "class_info": a QDict containing:
> + * - "desc": device class description
> + * - "class": device class number
Need to document how unknown classes are encoded (now: "desc" has value
"").
> + * - "id": a QDict containing:
> + * - "device": device ID
> + * - "vendor": vendor ID
> + * - "irq": device's IRQ if assigned (optional)
> + * - "qdev_id": qdev id string
> + * - "regions": a QList of QDicts, each QDict represents a
> + * memory region of this device
> + *
> + * The region QDict can be an I/O region or a memory region,
> + * the I/O region contains the following:
"An I/O region QDict", because there can be more than one.
> + *
> + * - "type": "io"
> + * - "bar": BAR number
> + * - "address": memory address
> + * - "size": memory size
> + *
> + * The memory region QDict contains the following:
Likewise, "A memory region QDict".
> + *
> + * - "type": "memory"
> + * - "bar": BAR number
> + * - "address": memory address
> + * - "size": memory size
> + * - "mem_type_64": true or false
> + * - "prefetch": true or false
> + */
> +void do_pci_info(Monitor *mon, QObject **ret_data)
> {
> + QList *bus_list;
> struct PCIHostBus *host;
> +
> + bus_list = qlist_new();
> +
> QLIST_FOREACH(host, &host_buses, next) {
> - pci_for_each_device(host->bus, 0, pci_info_device);
> + QObject *obj = pci_get_bus_dict(host->bus, 0);
> + if (obj) {
> + qlist_append_obj(bus_list, obj);
> + }
> }
> +
> + *ret_data = QOBJECT(bus_list);
> }
>
> static const char * const pci_nic_models[] = {
> diff --git a/hw/pci.h b/hw/pci.h
> index 9b5ae97..45edf75 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -2,6 +2,7 @@
> #define QEMU_PCI_H
>
> #include "qemu-common.h"
> +#include "qobject.h"
>
> #include "qdev.h"
>
> @@ -233,7 +234,8 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char
> *devaddr);
> int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
> unsigned *slotp);
>
> -void pci_info(Monitor *mon);
> +void do_pci_info_print(Monitor *mon, const QObject *data);
> +void do_pci_info(Monitor *mon, QObject **ret_data);
> PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
> pci_map_irq_fn map_irq, const char *name);
> PCIDevice *pci_bridge_get_device(PCIBus *bus);
> diff --git a/monitor.c b/monitor.c
> index 2403a97..7536c1e 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -2438,7 +2438,8 @@ static const mon_cmd_t info_cmds[] = {
> .args_type = "",
> .params = "",
> .help = "show PCI info",
> - .mhandler.info = pci_info,
> + .user_print = do_pci_info_print,
> + .mhandler.info_new = do_pci_info,
> },
> #if defined(TARGET_I386) || defined(TARGET_SH4)
> {