From 02e2da45c4601909d5105838323d5c529ec7010b Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 23 May 2009 00:05:19 +0100 Subject: [PATCH] Add common BusState Implement and use a common device bus state. The main side-effect is that creating a bus and attaching it to a parent device are no longer separate operations. For legacy code we allow a NULL parent, but that should go away eventually. Also tweak creation code to veriry theat a device in on the right bus. Signed-off-by: Paul Brook --- hw/acpi.c | 2 +- hw/apb_pci.c | 3 +- hw/grackle_pci.c | 3 +- hw/gt64xxx.c | 3 +- hw/i2c.c | 35 +++++++++--------- hw/i2c.h | 6 ++-- hw/mips_malta.c | 2 +- hw/musicpal.c | 2 +- hw/omap_i2c.c | 4 +-- hw/pc.c | 2 +- hw/pci.c | 37 +++++++++++++------ hw/pci.h | 3 +- hw/piix_pci.c | 3 +- hw/pl022.c | 3 +- hw/ppc4xx_pci.c | 3 +- hw/ppce500_pci.c | 3 +- hw/prep_pci.c | 3 +- hw/pxa2xx.c | 11 +++--- hw/qdev.c | 89 +++++++++++++++++++++++++++------------------- hw/qdev.h | 54 +++++++++++++++++++++------- hw/realview.c | 2 +- hw/sh_pci.c | 3 +- hw/spitz.c | 9 ++--- hw/ssi.c | 35 ++++++++++++------ hw/ssi.h | 3 +- hw/stellaris.c | 12 +++---- hw/sysbus.c | 20 ++++++++--- hw/unin_pci.c | 3 +- hw/versatile_pci.c | 4 +-- hw/versatilepb.c | 2 +- 30 files changed, 229 insertions(+), 135 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 0bbb2d81c4..fccae69dd6 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -548,7 +548,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); - s->smbus = i2c_init_bus(); + s->smbus = i2c_init_bus(NULL, "i2c"); s->irq = sci_irq; qemu_register_reset(piix4_reset, 0, s); diff --git a/hw/apb_pci.c b/hw/apb_pci.c index d6ce9f4aef..dac5cd3af8 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -231,7 +231,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, s = qemu_mallocz(sizeof(APBState)); /* Ultrasparc PBM main bus */ - s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32); + s->bus = pci_register_bus(NULL, "pci", + pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32); pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, pci_apb_config_write, s); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 8b170d6144..581d1c5d60 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -133,7 +133,8 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) int pci_mem_config, pci_mem_data; s = qemu_mallocz(sizeof(GrackleState)); - s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, + s->bus = pci_register_bus(NULL, "pci", + pci_grackle_set_irq, pci_grackle_map_irq, pic, 0, 4); pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 7fc91dd4a2..ce3ffe26bd 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1128,7 +1128,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); - s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq, + s->pci->bus = pci_register_bus(NULL, "pci", + pci_gt64120_set_irq, pci_gt64120_map_irq, pic, 144, 4); s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), diff --git a/hw/i2c.c b/hw/i2c.c index ce9de29b77..8a0c4d7a75 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -11,6 +11,7 @@ struct i2c_bus { + BusState qbus; i2c_slave *current_dev; i2c_slave *dev; int saved_address; @@ -39,11 +40,12 @@ static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id) } /* Create a new I2C bus. */ -i2c_bus *i2c_init_bus(void) +i2c_bus *i2c_init_bus(DeviceState *parent, const char *name) { i2c_bus *bus; - bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); + bus = FROM_QBUS(i2c_bus, qbus_create(BUS_TYPE_I2C, sizeof(i2c_bus), + parent, name)); register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); return bus; } @@ -63,20 +65,22 @@ int i2c_bus_busy(i2c_bus *bus) /* TODO: Make this handle multiple masters. */ int i2c_start_transfer(i2c_bus *bus, int address, int recv) { - i2c_slave *dev; + DeviceState *qdev; + i2c_slave *slave = NULL; - for (dev = bus->dev; dev; dev = dev->next) { - if (dev->address == address) + LIST_FOREACH(qdev, &bus->qbus.children, sibling) { + slave = I2C_SLAVE_FROM_QDEV(qdev); + if (slave->address == address) break; } - if (!dev) + if (!slave) return 1; /* If the bus is already busy, assume this is a repeated start condition. */ - bus->current_dev = dev; - dev->info->event(dev, recv ? I2C_START_RECV : I2C_START_SEND); + bus->current_dev = slave; + slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND); return 0; } @@ -130,23 +134,20 @@ void i2c_slave_save(QEMUFile *f, i2c_slave *dev) void i2c_slave_load(QEMUFile *f, i2c_slave *dev) { i2c_bus *bus; - bus = qdev_get_bus(&dev->qdev); + bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev)); dev->address = qemu_get_byte(f); if (bus->saved_address == dev->address) { bus->current_dev = dev; } } -static void i2c_slave_qdev_init(DeviceState *dev, void *opaque) +static void i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base) { - I2CSlaveInfo *info = opaque; + I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev); i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev); s->info = info; - s->bus = qdev_get_bus(dev); s->address = qdev_get_prop_int(dev, "address", 0); - s->next = s->bus->dev; - s->bus->dev = s; info->init(s); } @@ -154,14 +155,16 @@ static void i2c_slave_qdev_init(DeviceState *dev, void *opaque) void i2c_register_slave(const char *name, int size, I2CSlaveInfo *info) { assert(size >= sizeof(i2c_slave)); - qdev_register(name, size, i2c_slave_qdev_init, info); + info->qdev.init = i2c_slave_qdev_init; + info->qdev.bus_type = BUS_TYPE_I2C; + qdev_register(name, size, &info->qdev); } DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, int addr) { DeviceState *dev; - dev = qdev_create(bus, name); + dev = qdev_create(&bus->qbus, name); qdev_set_prop_int(dev, "address", addr); qdev_init(dev); return dev; diff --git a/hw/i2c.h b/hw/i2c.h index 4e5a1ac8f5..f15c70c5ed 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -25,6 +25,8 @@ typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event); typedef void (*i2c_slave_initfn)(i2c_slave *dev); typedef struct { + DeviceInfo qdev; + /* Callbacks provided by the device. */ i2c_slave_initfn init; i2c_event_cb event; @@ -39,11 +41,9 @@ struct i2c_slave /* Remaining fields for internal use by the I2C code. */ int address; - void *next; - i2c_bus *bus; }; -i2c_bus *i2c_init_bus(void); +i2c_bus *i2c_init_bus(DeviceState *parent, const char *name); void i2c_set_slave_address(i2c_slave *dev, int address); int i2c_bus_busy(i2c_bus *bus); int i2c_start_transfer(i2c_bus *bus, int address, int recv); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e71ecc124e..a300808639 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -907,7 +907,7 @@ void mips_malta_init (ram_addr_t ram_size, for (i = 0; i < 8; i++) { /* TODO: Populate SPD eeprom data. */ DeviceState *eeprom; - eeprom = qdev_create(smbus, "smbus-eeprom"); + eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); qdev_set_prop_int(eeprom, "address", 0x50 + i); qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256)); qdev_init(eeprom); diff --git a/hw/musicpal.c b/hw/musicpal.c index 16476f2d4c..1e0aff5cbb 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -431,7 +431,7 @@ static i2c_interface *musicpal_audio_init(qemu_irq irq) s->irq = irq; i2c = qemu_mallocz(sizeof(i2c_interface)); - i2c->bus = i2c_init_bus(); + i2c->bus = i2c_init_bus(NULL, "i2c"); i2c->current_addr = -1; s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR); diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index f98ac8d75b..c0dd3a5499 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -433,7 +433,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, s->irq = irq; s->drq[0] = dma[0]; s->drq[1] = dma[1]; - s->bus = i2c_init_bus(); + s->bus = i2c_init_bus(NULL, "i2c"); omap_i2c_reset(s); iomemtype = cpu_register_io_memory(0, omap_i2c_readfn, @@ -454,7 +454,7 @@ struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, s->irq = irq; s->drq[0] = dma[0]; s->drq[1] = dma[1]; - s->bus = i2c_init_bus(); + s->bus = i2c_init_bus(NULL, "i2c"); omap_i2c_reset(s); iomemtype = l4_register_io_memory(0, omap_i2c_readfn, diff --git a/hw/pc.c b/hw/pc.c index faaa60fe8c..66cc780ef9 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1105,7 +1105,7 @@ static void pc_init1(ram_addr_t ram_size, smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]); for (i = 0; i < 8; i++) { DeviceState *eeprom; - eeprom = qdev_create(smbus, "smbus-eeprom"); + eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); qdev_set_prop_int(eeprom, "address", 0x50 + i); qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256)); qdev_init(eeprom); diff --git a/hw/pci.c b/hw/pci.c index bdf39417cd..0ab5b94a7d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -30,6 +30,7 @@ //#define DEBUG_PCI struct PCIBus { + BusState qbus; int bus_num; int devfn_min; pci_set_irq_fn set_irq; @@ -87,13 +88,16 @@ static int pcibus_load(QEMUFile *f, void *opaque, int version_id) return 0; } -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, +PCIBus *pci_register_bus(DeviceState *parent, const char *name, + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, qemu_irq *pic, int devfn_min, int nirq) { PCIBus *bus; static int nbus = 0; - bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); + bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI, + sizeof(PCIBus) + (nirq * sizeof(int)), + parent, name)); bus->set_irq = set_irq; bus->map_irq = map_irq; bus->irq_opaque = pic; @@ -320,7 +324,7 @@ int pci_unregister_device(PCIDevice *pci_dev) qemu_free_irqs(pci_dev->irq); pci_irq_index--; pci_dev->bus->devices[pci_dev->devfn] = NULL; - qemu_free(pci_dev); + qdev_free(&pci_dev->qdev); return 0; } @@ -821,7 +825,7 @@ PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, for (i = 0; pci_nic_models[i]; i++) { if (strcmp(nd->model, pci_nic_models[i]) == 0) { - dev = qdev_create(bus, pci_nic_names[i]); + dev = qdev_create(&bus->qbus, pci_nic_names[i]); qdev_set_prop_int(dev, "devfn", devfn); qdev_set_netdev(dev, nd); qdev_init(dev); @@ -901,32 +905,43 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, return s->bus; } -static void pci_qdev_init(DeviceState *qdev, void *opaque) +typedef struct { + DeviceInfo qdev; + pci_qdev_initfn init; +} PCIDeviceInfo; + +static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base) { PCIDevice *pci_dev = (PCIDevice *)qdev; - pci_qdev_initfn init; + PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev); PCIBus *bus; int devfn; - init = opaque; - bus = qdev_get_bus(qdev); + bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); devfn = qdev_get_prop_int(qdev, "devfn", -1); pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn, NULL, NULL);//FIXME:config_read, config_write); assert(pci_dev); - init(pci_dev); + info->init(pci_dev); } void pci_qdev_register(const char *name, int size, pci_qdev_initfn init) { - qdev_register(name, size, pci_qdev_init, init); + PCIDeviceInfo *info; + + info = qemu_mallocz(sizeof(*info)); + info->init = init; + info->qdev.init = pci_qdev_init; + info->qdev.bus_type = BUS_TYPE_PCI; + + qdev_register(name, size, &info->qdev); } PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) { DeviceState *dev; - dev = qdev_create(bus, name); + dev = qdev_create(&bus->qbus, name); qdev_set_prop_int(dev, "devfn", devfn); qdev_init(dev); diff --git a/hw/pci.h b/hw/pci.h index 09f9799dcd..0405837f73 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -183,7 +183,8 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, +PCIBus *pci_register_bus(DeviceState *parent, const char *name, + pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, qemu_irq *pic, int devfn_min, int nirq); PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 2b19cc6887..914a65a310 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -176,7 +176,8 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) I440FXState *s; s = qemu_mallocz(sizeof(I440FXState)); - b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4); + b = pci_register_bus(NULL, "pci", + piix3_set_irq, pci_slot_get_pirq, pic, 0, 4); s->bus = b; register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); diff --git a/hw/pl022.c b/hw/pl022.c index 20d317c116..27cb7aff64 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -297,8 +297,7 @@ static void pl022_init(SysBusDevice *dev) pl022_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); - s->ssi = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi", s->ssi); + s->ssi = ssi_create_bus(&dev->qdev, "ssi"); pl022_reset(s); register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s); } diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 7ebfcc05fd..45ab3be21f 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -370,7 +370,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], controller = qemu_mallocz(sizeof(PPC4xxPCIState)); - controller->pci_state.bus = pci_register_bus(ppc4xx_pci_set_irq, + controller->pci_state.bus = pci_register_bus(NULL, "pci", + ppc4xx_pci_set_irq, ppc4xx_pci_map_irq, pci_irqs, 0, 4); diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 9eed890d44..79703a3ff1 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -317,7 +317,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) controller = qemu_mallocz(sizeof(PPCE500PCIState)); - controller->pci_state.bus = pci_register_bus(mpc85xx_pci_set_irq, + controller->pci_state.bus = pci_register_bus(NULL, "pci", + mpc85xx_pci_set_irq, mpc85xx_pci_map_irq, pci_irqs, 0x88, 4); d = pci_register_device(controller->pci_state.bus, diff --git a/hw/prep_pci.c b/hw/prep_pci.c index a97b845b43..e747e39721 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -136,7 +136,8 @@ PCIBus *pci_prep_init(qemu_irq *pic) int PPC_io_memory; s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 4); + s->bus = pci_register_bus(NULL, "pci", + prep_set_irq, prep_map_irq, pic, 0, 4); register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d54ad194bc..febe527491 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -863,8 +863,7 @@ static void pxa2xx_ssp_init(SysBusDevice *dev) register_savevm("pxa2xx_ssp", -1, 0, pxa2xx_ssp_save, pxa2xx_ssp_load, s); - s->bus = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi", s->bus); + s->bus = ssi_create_bus(&dev->qdev, "ssi"); } /* Real-Time Clock */ @@ -1500,12 +1499,12 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState)); /* FIXME: Should the slave device really be on a separate bus? */ - dev = i2c_create_slave(i2c_init_bus(), "pxa2xx-i2c-slave", 0); + dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev)); s->slave->host = s; s->irq = irq; - s->bus = i2c_init_bus(); + s->bus = i2c_init_bus(NULL, "i2c"); s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK); iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn, @@ -2117,7 +2116,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) DeviceState *dev; dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base, s->pic[pxa27x_ssp[i].irqn]); - s->ssp[i] = qdev_get_child_bus(dev, "ssi"); + s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } if (usb_enabled) { @@ -2229,7 +2228,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) DeviceState *dev; dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base, s->pic[pxa255_ssp[i].irqn]); - s->ssp[i] = qdev_get_child_bus(dev, "ssi"); + s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } if (usb_enabled) { diff --git a/hw/qdev.c b/hw/qdev.c index 9ed6f85cc4..b9278e9a5a 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -41,23 +41,18 @@ struct DeviceProperty { struct DeviceType { const char *name; - qdev_initfn init; - void *opaque; + DeviceInfo *info; int size; DeviceType *next; }; -struct ChildBusList { - const char *name; - void *ptr; - ChildBusList *next; -}; +/* This is a nasty hack to allow passing a NULL bus to qdev_create. */ +BusState *main_system_bus; static DeviceType *device_type_list; /* Register a new device type. */ -DeviceType *qdev_register(const char *name, int size, qdev_initfn init, - void *opaque) +void qdev_register(const char *name, int size, DeviceInfo *info) { DeviceType *t; @@ -68,16 +63,13 @@ DeviceType *qdev_register(const char *name, int size, qdev_initfn init, device_type_list = t; t->name = qemu_strdup(name); t->size = size; - t->init = init; - t->opaque = opaque; - - return t; + t->info = info; } /* Create a new device. This only initializes the device state structure and allows properties to be set. qdev_init should be called to initialize the actual device emulation. */ -DeviceState *qdev_create(void *bus, const char *name) +DeviceState *qdev_create(BusState *bus, const char *name) { DeviceType *t; DeviceState *dev; @@ -88,14 +80,28 @@ DeviceState *qdev_create(void *bus, const char *name) } } if (!t) { - fprintf(stderr, "Unknown device '%s'\n", name); - exit(1); + hw_error("Unknown device '%s'\n", name); } dev = qemu_mallocz(t->size); dev->name = name; dev->type = t; - dev->bus = bus; + + if (!bus) { + /* ???: This assumes system busses have no additional state. */ + if (!main_system_bus) { + main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState), + NULL, "main-system-bus"); + } + bus = main_system_bus; + } + if (t->info->bus_type != bus->type) { + /* TODO: Print bus type names. */ + hw_error("Device '%s' on wrong bus type (%d/%d)", name, + t->info->bus_type, bus->type); + } + dev->parent_bus = bus; + LIST_INSERT_HEAD(&bus->children, dev, sibling); return dev; } @@ -104,7 +110,14 @@ DeviceState *qdev_create(void *bus, const char *name) calling this function. */ void qdev_init(DeviceState *dev) { - dev->type->init(dev, dev->type->opaque); + dev->type->info->init(dev, dev->type->info); +} + +/* Unlink device from bus and free the structure. */ +void qdev_free(DeviceState *dev) +{ + LIST_REMOVE(dev, sibling); + free(dev); } static DeviceProperty *create_prop(DeviceState *dev, const char *name) @@ -169,9 +182,9 @@ CharDriverState *qdev_init_chardev(DeviceState *dev) } } -void *qdev_get_bus(DeviceState *dev) +BusState *qdev_get_parent_bus(DeviceState *dev) { - return dev->bus; + return dev->parent_bus; } static DeviceProperty *find_prop(DeviceState *dev, const char *name) @@ -267,30 +280,18 @@ BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type) return drives_table[index].bdrv; } -void *qdev_get_child_bus(DeviceState *dev, const char *name) +BusState *qdev_get_child_bus(DeviceState *dev, const char *name) { - ChildBusList *bus; + BusState *bus; - for (bus = dev->child_bus; bus; bus = bus->next) { + LIST_FOREACH(bus, &dev->child_bus, sibling) { if (strcmp(name, bus->name) == 0) { - return bus->ptr; + return bus; } } return NULL; } -void qdev_attach_child_bus(DeviceState *dev, const char *name, void *bus) -{ - ChildBusList *p; - - assert(!qdev_get_child_bus(dev, name)); - p = qemu_mallocz(sizeof(*p)); - p->name = qemu_strdup(name); - p->ptr = bus; - p->next = dev->child_bus; - dev->child_bus = p; -} - static int next_scsi_bus; /* Create a scsi bus, and attach devices to it. */ @@ -309,3 +310,19 @@ void scsi_bus_new(DeviceState *host, SCSIAttachFn attach) attach(host, drives_table[index].bdrv, unit); } } + +BusState *qbus_create(BusType type, size_t size, + DeviceState *parent, const char *name) +{ + BusState *bus; + + bus = qemu_mallocz(size); + bus->type = type; + bus->parent = parent; + bus->name = qemu_strdup(name); + LIST_INIT(&bus->children); + if (parent) { + LIST_INSERT_HEAD(&parent->child_bus, bus, sibling); + } + return bus; +} diff --git a/hw/qdev.h b/hw/qdev.h index 5a34f51038..0931bc19d6 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -2,20 +2,20 @@ #define QDEV_H #include "hw.h" +#include "sys-queue.h" typedef struct DeviceType DeviceType; typedef struct DeviceProperty DeviceProperty; -typedef struct ChildBusList ChildBusList; +typedef struct BusState BusState; /* This structure should not be accessed directly. We declare it here so that it can be embedded in individual device state structures. */ -struct DeviceState -{ +struct DeviceState { const char *name; DeviceType *type; - void *bus; + BusState *parent_bus; DeviceProperty *props; int num_irq_sink; qemu_irq *irq_sink; @@ -23,14 +23,32 @@ struct DeviceState qemu_irq *gpio_out; int num_gpio_in; qemu_irq *gpio_in; - ChildBusList *child_bus; + LIST_HEAD(, BusState) child_bus; NICInfo *nd; + LIST_ENTRY(DeviceState) sibling; +}; + +typedef enum { + BUS_TYPE_SYSTEM, + BUS_TYPE_PCI, + BUS_TYPE_SCSI, + BUS_TYPE_I2C, + BUS_TYPE_SSI +} BusType; + +struct BusState { + DeviceState *parent; + const char *name; + BusType type; + LIST_HEAD(, DeviceState) children; + LIST_ENTRY(BusState) sibling; }; /*** Board API. This should go away once we have a machine config file. ***/ -DeviceState *qdev_create(void *bus, const char *name); +DeviceState *qdev_create(BusState *bus, const char *name); void qdev_init(DeviceState *dev); +void qdev_free(DeviceState *dev); /* Set properties between creation and init. */ void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value); @@ -41,28 +59,33 @@ qemu_irq qdev_get_irq_sink(DeviceState *dev, int n); qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); -void *qdev_get_child_bus(DeviceState *dev, const char *name); +BusState *qdev_get_child_bus(DeviceState *dev, const char *name); /*** Device API. ***/ -typedef void (*qdev_initfn)(DeviceState *dev, void *opaque); +typedef struct DeviceInfo DeviceInfo; + +typedef void (*qdev_initfn)(DeviceState *dev, DeviceInfo *info); typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv, int unit); -DeviceType *qdev_register(const char *name, int size, qdev_initfn init, - void *opaque); +struct DeviceInfo { + qdev_initfn init; + BusType bus_type; +}; + +void qdev_register(const char *name, int size, DeviceInfo *info); /* Register device properties. */ void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq); void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); -void qdev_attach_child_bus(DeviceState *dev, const char *name, void *bus); void scsi_bus_new(DeviceState *host, SCSIAttachFn attach); CharDriverState *qdev_init_chardev(DeviceState *dev); -void *qdev_get_bus(DeviceState *dev); +BusState *qdev_get_parent_bus(DeviceState *dev); uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def); void *qdev_get_prop_ptr(DeviceState *dev, const char *name); @@ -76,4 +99,11 @@ void *qdev_get_prop_ptr(DeviceState *dev, const char *name); #define DO_UPCAST(type, field, dev) container_of(dev, type, field) #endif +/*** BUS API. ***/ + +BusState *qbus_create(BusType type, size_t size, + DeviceState *parent, const char *name); + +#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) + #endif diff --git a/hw/realview.c b/hw/realview.c index 49e07fd1d2..535f907626 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -109,7 +109,7 @@ static void realview_init(ram_addr_t ram_size, dev = sysbus_create_varargs("realview_pci", 0x60000000, pic[48], pic[49], pic[50], pic[51], NULL); - pci_bus = qdev_get_child_bus(dev, "pci"); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); } diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 3f79b1038b..2ec4b43bd9 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -174,7 +174,8 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, int mem, reg, iop; p = qemu_mallocz(sizeof(SHPCIC)); - p->bus = pci_register_bus(set_irq, map_irq, pic, devfn_min, nirq); + p->bus = pci_register_bus(NULL, "pci", + set_irq, map_irq, pic, devfn_min, nirq); p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice), -1, NULL, NULL); diff --git a/hw/spitz.c b/hw/spitz.c index dd167806c2..aa1487b20a 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -706,12 +706,9 @@ static void corgi_ssp_init(SSISlave *dev) CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3); - s->bus[0] = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]); - s->bus[1] = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi1", s->bus[1]); - s->bus[2] = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi2", s->bus[2]); + s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); + s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); + s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2"); register_savevm("spitz_ssp", -1, 1, spitz_ssp_save, spitz_ssp_load, s); } diff --git a/hw/ssi.c b/hw/ssi.c index 9dfdbe94f8..52b7b7c593 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -10,16 +10,21 @@ #include "ssi.h" struct SSIBus { - SSISlave *slave; + BusState qbus; }; -static void ssi_slave_init(DeviceState *dev, void *opaque) +static void ssi_slave_init(DeviceState *dev, DeviceInfo *base_info) { - SSISlaveInfo *info = opaque; + SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev); SSISlave *s = SSI_SLAVE_FROM_QDEV(dev); - SSIBus *bus = qdev_get_bus(dev); + SSIBus *bus; + + bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev)); + if (LIST_FIRST(&bus->qbus.children) != dev + || LIST_NEXT(dev, sibling) != NULL) { + hw_error("Too many devices on SSI bus"); + } - bus->slave = s; s->info = info; info->init(s); } @@ -27,26 +32,34 @@ static void ssi_slave_init(DeviceState *dev, void *opaque) void ssi_register_slave(const char *name, int size, SSISlaveInfo *info) { assert(size >= sizeof(SSISlave)); - qdev_register(name, size, ssi_slave_init, info); + info->qdev.init = ssi_slave_init; + info->qdev.bus_type = BUS_TYPE_SSI; + qdev_register(name, size, &info->qdev); } DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { DeviceState *dev; - dev = qdev_create(bus, name); + dev = qdev_create(&bus->qbus, name); qdev_init(dev); return dev; } -SSIBus *ssi_create_bus(void) +SSIBus *ssi_create_bus(DeviceState *parent, const char *name) { - return qemu_mallocz(sizeof(SSIBus)); + BusState *bus; + bus = qbus_create(BUS_TYPE_SSI, sizeof(SSIBus), parent, name); + return FROM_QBUS(SSIBus, bus); } uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { - if (!bus->slave) { + DeviceState *dev; + SSISlave *slave; + dev = LIST_FIRST(&bus->qbus.children); + if (!dev) { return 0; } - return bus->slave->info->transfer(bus->slave, val); + slave = SSI_SLAVE_FROM_QDEV(dev); + return slave->info->transfer(slave, val); } diff --git a/hw/ssi.h b/hw/ssi.h index aab740fc56..861c4849e7 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -17,6 +17,7 @@ typedef struct SSISlave SSISlave; /* Slave devices. */ typedef struct { + DeviceInfo qdev; void (*init)(SSISlave *dev); uint32_t (*transfer)(SSISlave *dev, uint32_t val); } SSISlaveInfo; @@ -34,7 +35,7 @@ void ssi_register_slave(const char *name, int size, SSISlaveInfo *info); DeviceState *ssi_create_slave(SSIBus *bus, const char *name); /* Master interface. */ -SSIBus *ssi_create_bus(void); +SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); diff --git a/hw/stellaris.c b/hw/stellaris.c index e7f3604f78..a107db7465 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -874,11 +874,11 @@ static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) static void stellaris_i2c_init(SysBusDevice * dev) { stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev); - i2c_bus *bus = i2c_init_bus(); + i2c_bus *bus; int iomemtype; sysbus_init_irq(dev, &s->irq); - qdev_attach_child_bus(&dev->qdev, "i2c", bus); + bus = i2c_init_bus(&dev->qdev, "i2c"); s->bus = bus; iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn, @@ -1239,10 +1239,8 @@ static void stellaris_ssi_bus_init(SSISlave *dev) { stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - s->bus[0] = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]); - s->bus[1] = ssi_create_bus(); - qdev_attach_child_bus(&dev->qdev, "ssi1", s->bus[1]); + s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); + s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); register_savevm("stellaris_ssi_bus", -1, 1, @@ -1320,7 +1318,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 12)) { DeviceState *dev; dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]); - i2c = qdev_get_child_bus(dev, "i2c"); + i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); if (board->peripherals & BP_OLED_I2C) { i2c_create_slave(i2c, "ssd0303", 0x3d); } diff --git a/hw/sysbus.c b/hw/sysbus.c index e6cb7dd78b..13d81f541f 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -21,6 +21,11 @@ #include "sysbus.h" #include "sysemu.h" +typedef struct { + DeviceInfo qdev; + sysbus_initfn init; +} SysBusDeviceInfo; + void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) { assert(n >= 0 && n < dev->num_irq); @@ -97,17 +102,24 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size, dev->mmio[n].cb = cb; } -static void sysbus_device_init(DeviceState *dev, void *opaque) +static void sysbus_device_init(DeviceState *dev, DeviceInfo *base) { - sysbus_initfn init = (sysbus_initfn)opaque; + SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev); - init(sysbus_from_qdev(dev)); + info->init(sysbus_from_qdev(dev)); } void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init) { + SysBusDeviceInfo *info; + + info = qemu_mallocz(sizeof(*info)); + info->init = init; + info->qdev.init = sysbus_device_init; + info->qdev.bus_type = BUS_TYPE_SYSTEM; + assert(size >= sizeof(SysBusDevice)); - qdev_register(name, size, sysbus_device_init, init); + qdev_register(name, size, &info->qdev); } DeviceState *sysbus_create_varargs(const char *name, diff --git a/hw/unin_pci.c b/hw/unin_pci.c index b9c1821d82..a9ef217338 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -175,7 +175,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic) /* Use values found on a real PowerMac */ /* Uninorth main bus */ s = qemu_mallocz(sizeof(UNINState)); - s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq, + s->bus = pci_register_bus(NULL, "pci", + pci_unin_set_irq, pci_unin_map_irq, pic, 11 << 3, 4); pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 720742c0e0..e454d498d7 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -118,9 +118,9 @@ static void pci_vpb_init(SysBusDevice *dev) for (i = 0; i < 4; i++) { sysbus_init_irq(dev, &s->irq[i]); } - bus = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, s->irq, + bus = pci_register_bus(&dev->qdev, "pci", + pci_vpb_set_irq, pci_vpb_map_irq, s->irq, 11 << 3, 4); - qdev_attach_child_bus(&dev->qdev, "pci", bus); /* ??? Register memory space. */ diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 5ae57e329d..eed97d6db7 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -201,7 +201,7 @@ static void versatile_init(ram_addr_t ram_size, dev = sysbus_create_varargs("versatile_pci", 0x40000000, sic[27], sic[28], sic[29], sic[30], NULL); - pci_bus = qdev_get_child_bus(dev, "pci"); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); /* The Versatile PCI bridge does not provide access to PCI IO space, so many of the qemu PCI devices are not useable. */