Message ID | 1426791181-23831-10-git-send-email-marcel@redhat.com |
---|---|
State | New |
Headers | show |
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 <marcel.a@redhat.com> (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), "%s@%x", > + 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
On 27/04/2015 13:14, Michael S. Tsirkin wrote: >> + * >> > + * 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. It's BSD. > You will need to find who contributed this code you are moving > and get ack from them ... Simpler to keep BSD. Paolo
On 04/27/2015 02:35 PM, Paolo Bonzini wrote: > > On 27/04/2015 13:14, Michael S. Tsirkin wrote: >>> + * >>>> + * 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. > > It's BSD. > >> You will need to find who contributed this code you are moving >> and get ack from them ... > > Simpler to keep BSD. Sure, will do. Thanks, Marcel > > Paolo >
On Mon, Apr 27, 2015 at 02:49:16PM +0300, Marcel Apfelbaum wrote: > On 04/27/2015 02:35 PM, Paolo Bonzini wrote: > > > >On 27/04/2015 13:14, Michael S. Tsirkin wrote: > >>>+ * > >>>>+ * 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. > > > >It's BSD. > > > >>You will need to find who contributed this code you are moving > >>and get ack from them ... > > > >Simpler to keep BSD. > Sure, will do. > > Thanks, > Marcel I'd say just keep it within pci.c for now, the smaller the patchset the better. Refactor later. > > > >Paolo > >
On 04/27/2015 02:14 PM, Michael S. Tsirkin wrote: > 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. There were a lot of code dependencies. I moved the minimum code in order to be able to add code specific to PCIBus. > > >> 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? Well, now yes :) > >> + * >> + * Authors: >> + * Marcel Apfelbaum <marcel.a@redhat.com> (split out from pci.c) > > You don't become the only Author just by moving code around. > Better drop this line. I was following an example of the latest code movement at that time in QEMU. Anyway, I will remove that 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 ... I'll keep it as BSD as Paolo suggested. > >> + */ >> +#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), "%s@%x", >> + 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. It always was like that. We need this because of the code movement. > >> >> 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? There are several patches on this series depending on this. Of course I can manually apply them, does it worth it? Thanks, Marcel > >> -- >> 2.1.0
Paolo Bonzini <pbonzini@redhat.com> writes: > On 27/04/2015 13:14, Michael S. Tsirkin wrote: >>> + * >>> > + * 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. > > It's BSD. > >> You will need to find who contributed this code you are moving >> and get ack from them ... > > Simpler to keep BSD. Just for completeness: you're free to GPL a derived work. The folks who BSD-licensed it to you may consider that offensive, but the law doesn't consider it wrong. You may care a whole lot more for how these folks feel about you than what the law permits you to do. I'd consider switching to GPL only if I made substantial changes.
On 04/28/2015 10:31 AM, Markus Armbruster wrote: > Paolo Bonzini <pbonzini@redhat.com> writes: > >> On 27/04/2015 13:14, Michael S. Tsirkin wrote: >>>> + * >>>>> + * 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. >> >> It's BSD. >> >>> You will need to find who contributed this code you are moving >>> and get ack from them ... >> >> Simpler to keep BSD. > > Just for completeness: you're free to GPL a derived work. The folks who > BSD-licensed it to you may consider that offensive, but the law doesn't > consider it wrong. > > You may care a whole lot more for how these folks feel about you than > what the law permits you to do. > > I'd consider switching to GPL only if I made substantial changes. > Thanks Markus, Since I only moved some code around, I'll keep it BSD. Marcel
On Mon, Apr 27, 2015 at 03:26:44PM +0300, Marcel Apfelbaum wrote: > On 04/27/2015 02:14 PM, Michael S. Tsirkin wrote: > >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. > There were a lot of code dependencies. I moved the minimum code in order > to be able to add code specific to PCIBus. Interfaces need to make sense, this one feels like you randomly moved out parts that your patch happens to need. Just keep it all in pci.c for now.
On 04/28/2015 11:30 AM, Michael S. Tsirkin wrote: > On Mon, Apr 27, 2015 at 03:26:44PM +0300, Marcel Apfelbaum wrote: >> On 04/27/2015 02:14 PM, Michael S. Tsirkin wrote: >>> 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. >> There were a lot of code dependencies. I moved the minimum code in order >> to be able to add code specific to PCIBus. > > Interfaces need to make sense, this one feels like you randomly moved out > parts that your patch happens to need. > Just keep it all in pci.c for now. > OK, I'll make the changes for next version. Thanks, Marcel
diff --git a/arch_init.c b/arch_init.c index 691b5e2..cbebf6d 100644 --- a/arch_init.c +++ b/arch_init.c @@ -37,6 +37,7 @@ #include "audio/audio.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/audio/audio.h" #include "sysemu/kvm.h" #include "migration/migration.h" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 62af946..d3fad5d 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -8,6 +8,7 @@ #include "cpu.h" #include "hw/hw.h" +#include "hw/pci/pci_bus.h" #include "hw/devices.h" #include "sysemu/sysemu.h" #include "alpha_sys.h" diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 10fcca3..c4ca6f3 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -25,6 +25,7 @@ #include "hw/hw.h" #include "hw/mips/mips.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/i386/pc.h" #include "exec/address-spaces.h" diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 8bdd569..49e1122 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -41,6 +41,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/i386/pc.h" #include "hw/mips/mips.h" #include "hw/pci/pci_host.h" diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index bfe707a..89745cd 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -26,6 +26,7 @@ #include "hw/pci/pci_host.h" #include "hw/ppc/mac.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" /* debug Grackle */ //#define DEBUG_GRACKLE diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 723836f..292b6e9 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -25,6 +25,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/isa/isa.h" #include "hw/sysbus.h" diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 613ba73..4363951 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -17,6 +17,7 @@ #include "hw/hw.h" #include "hw/ppc/e500-ccsr.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "hw/pci-host/ppce500.h" diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index c8827cc..5dd559e 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -28,6 +28,7 @@ * THE SOFTWARE. */ #include "hw/hw.h" +#include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" #include "qapi/visitor.h" diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 53f2b59..1406b42 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -24,6 +24,7 @@ #include "hw/hw.h" #include "hw/ppc/mac.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" /* debug UniNorth */ diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs index 9f905e6..a05cca0 100644 --- a/hw/pci/Makefile.objs +++ b/hw/pci/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bus.o common-obj-$(CONFIG_PCI) += msix.o msi.o common-obj-$(CONFIG_PCI) += shpc.o common-obj-$(CONFIG_PCI) += slotid_cap.o diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 6941a82..cb63a21 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -45,11 +45,6 @@ # define PCI_DPRINTF(format, ...) do { } while (0) #endif -static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); -static char *pcibus_get_dev_path(DeviceState *dev); -static char *pcibus_get_fw_dev_path(DeviceState *dev); -static void pcibus_reset(BusState *qbus); - static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), DEFINE_PROP_STRING("romfile", PCIDevice, romfile), @@ -61,58 +56,11 @@ static Property pci_props[] = { DEFINE_PROP_END_OF_LIST() }; -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); -} - -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 const TypeInfo pcie_bus_info = { .name = TYPE_PCIE_BUS, .parent = TYPE_PCI_BUS, }; -static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); static void pci_update_mappings(PCIDevice *d); static void pci_irq_handler(void *opaque, int irq_num, int level); static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, Error **); @@ -185,7 +133,7 @@ void pci_device_deassert_intx(PCIDevice *dev) } } -static void pci_do_device_reset(PCIDevice *dev) +void pci_do_device_reset(PCIDevice *dev) { int r; @@ -230,27 +178,6 @@ void pci_device_reset(PCIDevice *dev) pci_do_device_reset(dev); } -/* - * 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_host_bus_register(PCIBus *bus, DeviceState *parent) { PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent); @@ -1301,74 +1228,6 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; } -/***********************************************************/ -/* monitor info on PCI */ - -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} -}; - static void pci_for_each_device_under_bus(PCIBus *bus, void (*fn)(PCIBus *b, PCIDevice *d, void *opaque), @@ -1396,161 +1255,6 @@ void pci_for_each_device(PCIBus *bus, int bus_num, } } -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 PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num); - -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; -} - -static 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 PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) { PciInfo *info = NULL; @@ -1684,50 +1388,6 @@ PCIDevice *pci_vga_init(PCIBus *bus) } } -/* 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]; -} - -static 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; -} - void pci_for_each_bus_depth_first(PCIBus *bus, void *(*begin)(PCIBus *bus, void *parent_state), void (*end)(PCIBus *bus, void *state), @@ -2140,135 +1800,6 @@ uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) return pci_find_capability_list(pdev, cap_id, NULL); } -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 *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), "%s@%x", - 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 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 int pci_qdev_find_recursive(PCIBus *bus, const char *id, PCIDevice **pdev) { @@ -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); } 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 + * + * Authors: + * Marcel Apfelbaum <marcel.a@redhat.com> (split out from pci.c) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#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), "%s@%x", + 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); 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;
This refactoring moves all the code needed (recursively) to register TYPE_PCI_BUS type to a new file hw/pci/pci_bus.c . This allows to properly add new functionality to the pci bus class. Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> --- arch_init.c | 1 + hw/alpha/typhoon.c | 1 + hw/mips/gt64xxx_pci.c | 1 + hw/pci-host/bonito.c | 1 + hw/pci-host/grackle.c | 1 + hw/pci-host/piix.c | 1 + hw/pci-host/ppce500.c | 1 + hw/pci-host/q35.c | 1 + hw/pci-host/uninorth.c | 1 + hw/pci/Makefile.objs | 2 +- hw/pci/pci.c | 472 +-------------------------------------------- hw/pci/pci_bus.c | 491 +++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/ppc4xx_pci.c | 1 + hw/sh4/r2d.c | 1 + hw/sh4/sh_pci.c | 1 + include/hw/pci/pci.h | 3 +- include/hw/pci/pci_bus.h | 8 + 17 files changed, 514 insertions(+), 474 deletions(-) create mode 100644 hw/pci/pci_bus.c