[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH V6 for-2.3 09/26] hw/pci: move pci bus related c
From: |
Michael S. Tsirkin |
Subject: |
Re: [Qemu-devel] [PATCH V6 for-2.3 09/26] hw/pci: move pci bus related code to separate files |
Date: |
Mon, 27 Apr 2015 13:14:16 +0200 |
On Thu, Mar 19, 2015 at 08:52:44PM +0200, Marcel Apfelbaum wrote:
> @@ -2414,7 +1945,6 @@ static const TypeInfo pci_device_type_info = {
>
> static void pci_register_types(void)
> {
> - type_register_static(&pci_bus_info);
> type_register_static(&pcie_bus_info);
> type_register_static(&pci_device_type_info);
> }
So pcie bus is not moved. This seems pretty inconsistent.
> diff --git a/hw/pci/pci_bus.c b/hw/pci/pci_bus.c
> new file mode 100644
> index 0000000..d156194
> --- /dev/null
> +++ b/hw/pci/pci_bus.c
> @@ -0,0 +1,491 @@
> +/*
> + * PCI Bus
> + *
> + * Copyright (C) 2014 Red Hat Inc
It's 2015 isn't it?
> + *
> + * Authors:
> + * Marcel Apfelbaum <address@hidden> (split out from pci.c)
You don't become the only Author just by moving code around.
Better drop this line.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
The file you are moving this from is GPL only.
You will need to find who contributed this code you are moving
and get ack from them ...
> + */
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> +#include "hw/pci/pci_bridge.h"
> +#include "monitor/monitor.h"
> +
> +typedef struct {
> + uint16_t class;
> + const char *desc;
> + const char *fw_name;
> + uint16_t fw_ign_bits;
> +} pci_class_desc;
> +
> +static const pci_class_desc pci_class_descriptions[] = {
> + { 0x0001, "VGA controller", "display"},
> + { 0x0100, "SCSI controller", "scsi"},
> + { 0x0101, "IDE controller", "ide"},
> + { 0x0102, "Floppy controller", "fdc"},
> + { 0x0103, "IPI controller", "ipi"},
> + { 0x0104, "RAID controller", "raid"},
> + { 0x0106, "SATA controller"},
> + { 0x0107, "SAS controller"},
> + { 0x0180, "Storage controller"},
> + { 0x0200, "Ethernet controller", "ethernet"},
> + { 0x0201, "Token Ring controller", "token-ring"},
> + { 0x0202, "FDDI controller", "fddi"},
> + { 0x0203, "ATM controller", "atm"},
> + { 0x0280, "Network controller"},
> + { 0x0300, "VGA controller", "display", 0x00ff},
> + { 0x0301, "XGA controller"},
> + { 0x0302, "3D controller"},
> + { 0x0380, "Display controller"},
> + { 0x0400, "Video controller", "video"},
> + { 0x0401, "Audio controller", "sound"},
> + { 0x0402, "Phone"},
> + { 0x0403, "Audio controller", "sound"},
> + { 0x0480, "Multimedia controller"},
> + { 0x0500, "RAM controller", "memory"},
> + { 0x0501, "Flash controller", "flash"},
> + { 0x0580, "Memory controller"},
> + { 0x0600, "Host bridge", "host"},
> + { 0x0601, "ISA bridge", "isa"},
> + { 0x0602, "EISA bridge", "eisa"},
> + { 0x0603, "MC bridge", "mca"},
> + { 0x0604, "PCI bridge", "pci-bridge"},
> + { 0x0605, "PCMCIA bridge", "pcmcia"},
> + { 0x0606, "NUBUS bridge", "nubus"},
> + { 0x0607, "CARDBUS bridge", "cardbus"},
> + { 0x0608, "RACEWAY bridge"},
> + { 0x0680, "Bridge"},
> + { 0x0700, "Serial port", "serial"},
> + { 0x0701, "Parallel port", "parallel"},
> + { 0x0800, "Interrupt controller", "interrupt-controller"},
> + { 0x0801, "DMA controller", "dma-controller"},
> + { 0x0802, "Timer", "timer"},
> + { 0x0803, "RTC", "rtc"},
> + { 0x0900, "Keyboard", "keyboard"},
> + { 0x0901, "Pen", "pen"},
> + { 0x0902, "Mouse", "mouse"},
> + { 0x0A00, "Dock station", "dock", 0x00ff},
> + { 0x0B00, "i386 cpu", "cpu", 0x00ff},
> + { 0x0c00, "Fireware contorller", "fireware"},
> + { 0x0c01, "Access bus controller", "access-bus"},
> + { 0x0c02, "SSA controller", "ssa"},
> + { 0x0c03, "USB controller", "usb"},
> + { 0x0c04, "Fibre channel controller", "fibre-channel"},
> + { 0x0c05, "SMBus"},
> + { 0, NULL}
> +};
> +
> +/* Whether a given bus number is in range of the secondary
> + * bus of the given bridge device. */
> +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
> +{
> + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
> + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset.
> */ &&
> + dev->config[PCI_SECONDARY_BUS] < bus_num &&
> + bus_num <= dev->config[PCI_SUBORDINATE_BUS];
> +}
> +
> +PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
> +{
> + PCIBus *sec;
> +
> + if (!bus) {
> + return NULL;
> + }
> +
> + if (pci_bus_num(bus) == bus_num) {
> + return bus;
> + }
> +
> + /* Consider all bus numbers in range for the host pci bridge. */
> + if (!pci_bus_is_root(bus) &&
> + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
> + return NULL;
> + }
> +
> + /* try child bus */
> + for (; bus; bus = sec) {
> + QLIST_FOREACH(sec, &bus->child, sibling) {
> + assert(!pci_bus_is_root(sec));
> + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
> + return sec;
> + }
> + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
> + break;
> + }
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static const pci_class_desc *get_class_desc(int class)
> +{
> + const pci_class_desc *desc;
> +
> + desc = pci_class_descriptions;
> + while (desc->desc && class != desc->class) {
> + desc++;
> + }
> +
> + return desc;
> +}
> +
> +static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
> +{
> + PciMemoryRegionList *head = NULL, *cur_item = NULL;
> + int i;
> +
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + const PCIIORegion *r = &dev->io_regions[i];
> + PciMemoryRegionList *region;
> +
> + if (!r->size) {
> + continue;
> + }
> +
> + region = g_malloc0(sizeof(*region));
> + region->value = g_malloc0(sizeof(*region->value));
> +
> + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
> + region->value->type = g_strdup("io");
> + } else {
> + 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);
> + }
> +
> + 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 head;
> +}
> +
> +static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
> + int bus_num)
> +{
> + PciBridgeInfo *info;
> +
> + info = g_malloc0(sizeof(*info));
> +
> + info->bus.number = dev->config[PCI_PRIMARY_BUS];
> + info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
> + info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
> +
> + 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_nr(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.q_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) {
> + 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) {
> + info->has_pci_bridge = true;
> + info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
> + }
> +
> + return info;
> +}
> +
> +PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
> +{
> + PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
> + PCIDevice *dev;
> + int devfn;
> +
> + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
> + dev = bus->devices[devfn];
> + if (dev) {
> + 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 head;
> +}
> +
> +
> +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + const pci_class_desc *desc;
> + char ctxt[64];
> + PCIIORegion *r;
> + int i, class;
> +
> + class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> + desc = pci_class_descriptions;
> + while (desc->desc && class != desc->class) {
> + desc++;
> + }
> + if (desc->desc) {
> + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
> + } else {
> + snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
> + }
> +
> + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
> + "pci id %04x:%04x (sub %04x:%04x)\n",
> + indent, "", ctxt, pci_bus_num(d->bus),
> + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
> + pci_get_word(d->config + PCI_VENDOR_ID),
> + pci_get_word(d->config + PCI_DEVICE_ID),
> + pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
> + pci_get_word(d->config + PCI_SUBSYSTEM_ID));
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + r = &d->io_regions[i];
> + if (!r->size) {
> + continue;
> + }
> + monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
> + " [0x%"FMT_PCIBUS"]\n",
> + indent, "",
> + i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" :
> "mem",
> + r->addr, r->addr + r->size - 1);
> + }
> +}
> +
> +static char *pcibus_get_dev_path(DeviceState *dev)
> +{
> + PCIDevice *d = container_of(dev, PCIDevice, qdev);
> + PCIDevice *t;
> + int slot_depth;
> + /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
> + * 00 is added here to make this format compatible with
> + * domain:Bus:Slot.Func for systems without nested PCI bridges.
> + * Slot.Function list specifies the slot and function numbers for all
> + * devices on the path from root to the specific device. */
> + const char *root_bus_path;
> + int root_bus_len;
> + char slot[] = ":SS.F";
> + int slot_len = sizeof slot - 1 /* For '\0' */;
> + int path_len;
> + char *path, *p;
> + int s;
> +
> + root_bus_path = pci_root_bus_path(d);
> + root_bus_len = strlen(root_bus_path);
> +
> + /* Calculate # of slots on path between device and root. */;
> + slot_depth = 0;
> + for (t = d; t; t = t->bus->parent_dev) {
> + ++slot_depth;
> + }
> +
> + path_len = root_bus_len + slot_len * slot_depth;
> +
> + /* Allocate memory, fill in the terminating null byte. */
> + path = g_malloc(path_len + 1 /* For '\0' */);
> + path[path_len] = '\0';
> +
> + memcpy(path, root_bus_path, root_bus_len);
> +
> + /* Fill in slot numbers. We walk up from device to root, so need to print
> + * them in the reverse order, last to first. */
> + p = path + path_len;
> + for (t = d; t; t = t->bus->parent_dev) {
> + p -= slot_len;
> + s = snprintf(slot, sizeof slot, ":%02x.%x",
> + PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
> + assert(s == slot_len);
> + memcpy(p, slot, slot_len);
> + }
> +
> + return path;
> +}
> +
> +static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + const char *name = NULL;
> + const pci_class_desc *desc = pci_class_descriptions;
> + int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
> +
> + while (desc->desc &&
> + (class & ~desc->fw_ign_bits) !=
> + (desc->class & ~desc->fw_ign_bits)) {
> + desc++;
> + }
> +
> + if (desc->desc) {
> + name = desc->fw_name;
> + }
> +
> + if (name) {
> + pstrcpy(buf, len, name);
> + } else {
> + snprintf(buf, len, "pci%04x,%04x",
> + pci_get_word(d->config + PCI_VENDOR_ID),
> + pci_get_word(d->config + PCI_DEVICE_ID));
> + }
> +
> + return buf;
> +}
> +
> +static char *pcibus_get_fw_dev_path(DeviceState *dev)
> +{
> + PCIDevice *d = (PCIDevice *)dev;
> + char path[50], name[33];
> + int off;
> +
> + off = snprintf(path, sizeof(path), "address@hidden",
> + pci_dev_fw_name(dev, name, sizeof name),
> + PCI_SLOT(d->devfn));
> + if (PCI_FUNC(d->devfn)) {
> + snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
> + }
> + return g_strdup(path);
> +}
> +
> +static const VMStateDescription vmstate_pcibus = {
> + .name = "PCIBUS",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_INT32_EQUAL(nirq, PCIBus),
> + VMSTATE_VARRAY_INT32(irq_count, PCIBus,
> + nirq, 0, vmstate_info_int32,
> + int32_t),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void pci_bus_realize(BusState *qbus, Error **errp)
> +{
> + PCIBus *bus = PCI_BUS(qbus);
> +
> + vmstate_register(NULL, -1, &vmstate_pcibus, bus);
> +}
> +
> +static void pci_bus_unrealize(BusState *qbus, Error **errp)
> +{
> + PCIBus *bus = PCI_BUS(qbus);
> +
> + vmstate_unregister(NULL, &vmstate_pcibus, bus);
> +}
> +
> +/*
> + * Trigger pci bus reset under a given bus.
> + * Called via qbus_reset_all on RST# assert, after the devices
> + * have been reset qdev_reset_all-ed already.
> + */
> +static void pcibus_reset(BusState *qbus)
> +{
> + PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
> + if (bus->devices[i]) {
> + pci_do_device_reset(bus->devices[i]);
> + }
> + }
> +
> + for (i = 0; i < bus->nirq; i++) {
> + assert(bus->irq_count[i] == 0);
> + }
> +}
> +
> +static void pci_bus_class_init(ObjectClass *klass, void *data)
> +{
> + BusClass *k = BUS_CLASS(klass);
> +
> + k->print_dev = pcibus_dev_print;
> + k->get_dev_path = pcibus_get_dev_path;
> + k->get_fw_dev_path = pcibus_get_fw_dev_path;
> + k->realize = pci_bus_realize;
> + k->unrealize = pci_bus_unrealize;
> + k->reset = pcibus_reset;
> +}
> +
> +static const TypeInfo pci_bus_info = {
> + .name = TYPE_PCI_BUS,
> + .parent = TYPE_BUS,
> + .instance_size = sizeof(PCIBus),
> + .class_init = pci_bus_class_init,
> +};
> +
> +static void pci_bus_register_types(void)
> +{
> + type_register_static(&pci_bus_info);
> +}
> +
> +type_init(pci_bus_register_types)
> diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
> index 0bb3cdb..f5847bc 100644
> --- a/hw/ppc/ppc4xx_pci.c
> +++ b/hw/ppc/ppc4xx_pci.c
> @@ -23,6 +23,7 @@
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/ppc4xx.h"
> #include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> #include "hw/pci/pci_host.h"
> #include "exec/address-spaces.h"
>
> diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
> index d1d0847..8dd2ce3 100644
> --- a/hw/sh4/r2d.c
> +++ b/hw/sh4/r2d.c
> @@ -30,6 +30,7 @@
> #include "sysemu/sysemu.h"
> #include "hw/boards.h"
> #include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> #include "net/net.h"
> #include "sh7750_regs.h"
> #include "hw/ide.h"
> diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c
> index a2f6d9e..f02e998 100644
> --- a/hw/sh4/sh_pci.c
> +++ b/hw/sh4/sh_pci.c
> @@ -24,6 +24,7 @@
> #include "hw/sysbus.h"
> #include "hw/sh4/sh.h"
> #include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> #include "hw/pci/pci_host.h"
> #include "qemu/bswap.h"
> #include "exec/address-spaces.h"
> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
> index be2d9b8..47077cd 100644
> --- a/include/hw/pci/pci.h
> +++ b/include/hw/pci/pci.h
> @@ -337,8 +337,6 @@ typedef void (*pci_set_irq_fn)(void *opaque, int irq_num,
> int level);
> typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
> typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
>
> -#define TYPE_PCI_BUS "PCI"
> -#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
> #define TYPE_PCIE_BUS "PCIE"
>
> bool pci_bus_is_express(PCIBus *bus);
> @@ -370,6 +368,7 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
> void pci_device_set_intx_routing_notifier(PCIDevice *dev,
> PCIINTxRoutingNotifier notifier);
> void pci_device_reset(PCIDevice *dev);
> +void pci_do_device_reset(PCIDevice *dev);
I don't like it that there are two reset functions now.
>
> PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
> const char *default_model,
> diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
> index fabaeee..ea427a3 100644
> --- a/include/hw/pci/pci_bus.h
> +++ b/include/hw/pci/pci_bus.h
> @@ -1,6 +1,8 @@
> #ifndef QEMU_PCI_BUS_H
> #define QEMU_PCI_BUS_H
>
> +#include "hw/pci/pci.h"
> +
> /*
> * PCI Bus and Bridge datastructures.
> *
> @@ -8,6 +10,12 @@
> * use accessor functions in pci.h, pci_bridge.h
> */
>
> +PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
> +PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
> +
> +#define TYPE_PCI_BUS "PCI"
> +#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
> +
> struct PCIBus {
> BusState qbus;
> PCIIOMMUFunc iommu_fn;
Can we drop this patch, do refactoring on top later?
> --
> 2.1.0
- Re: [Qemu-devel] [PATCH V6 for-2.3 09/26] hw/pci: move pci bus related code to separate files,
Michael S. Tsirkin <=