1aae9460eSPaul Brook /* 2aae9460eSPaul Brook * System (CPU) Bus device support code 3aae9460eSPaul Brook * 4aae9460eSPaul Brook * Copyright (c) 2009 CodeSourcery 5aae9460eSPaul Brook * 6aae9460eSPaul Brook * This library is free software; you can redistribute it and/or 7aae9460eSPaul Brook * modify it under the terms of the GNU Lesser General Public 8aae9460eSPaul Brook * License as published by the Free Software Foundation; either 9aae9460eSPaul Brook * version 2 of the License, or (at your option) any later version. 10aae9460eSPaul Brook * 11aae9460eSPaul Brook * This library is distributed in the hope that it will be useful, 12aae9460eSPaul Brook * but WITHOUT ANY WARRANTY; without even the implied warranty of 13aae9460eSPaul Brook * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14aae9460eSPaul Brook * Lesser General Public License for more details. 15aae9460eSPaul Brook * 16aae9460eSPaul Brook * You should have received a copy of the GNU Lesser General Public 178167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18aae9460eSPaul Brook */ 19aae9460eSPaul Brook 2083c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2183c9089eSPaolo Bonzini #include "monitor/monitor.h" 22022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 23aae9460eSPaul Brook 2410c4c98aSGerd Hoffmann static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); 25c646f74fSGleb Natapov static char *sysbus_get_fw_dev_path(DeviceState *dev); 2610c4c98aSGerd Hoffmann 270d936928SAnthony Liguori static void system_bus_class_init(ObjectClass *klass, void *data) 280d936928SAnthony Liguori { 290d936928SAnthony Liguori BusClass *k = BUS_CLASS(klass); 300d936928SAnthony Liguori 310d936928SAnthony Liguori k->print_dev = sysbus_dev_print; 320d936928SAnthony Liguori k->get_fw_dev_path = sysbus_get_fw_dev_path; 330d936928SAnthony Liguori } 340d936928SAnthony Liguori 350d936928SAnthony Liguori static const TypeInfo system_bus_info = { 360d936928SAnthony Liguori .name = TYPE_SYSTEM_BUS, 370d936928SAnthony Liguori .parent = TYPE_BUS, 380d936928SAnthony Liguori .instance_size = sizeof(BusState), 390d936928SAnthony Liguori .class_init = system_bus_class_init, 4010c4c98aSGerd Hoffmann }; 4110c4c98aSGerd Hoffmann 42aae9460eSPaul Brook void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) 43aae9460eSPaul Brook { 44aae9460eSPaul Brook assert(n >= 0 && n < dev->num_irq); 45660f11beSBlue Swirl dev->irqs[n] = NULL; 46aae9460eSPaul Brook if (dev->irqp[n]) { 47aae9460eSPaul Brook *dev->irqp[n] = irq; 48aae9460eSPaul Brook } 49aae9460eSPaul Brook } 50aae9460eSPaul Brook 517feb640cSAlexey Korolev static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr, 527feb640cSAlexey Korolev bool may_overlap, unsigned priority) 53aae9460eSPaul Brook { 54aae9460eSPaul Brook assert(n >= 0 && n < dev->num_mmio); 55aae9460eSPaul Brook 56aae9460eSPaul Brook if (dev->mmio[n].addr == addr) { 57aae9460eSPaul Brook /* ??? region already mapped here. */ 58aae9460eSPaul Brook return; 59aae9460eSPaul Brook } 60a8170e5eSAvi Kivity if (dev->mmio[n].addr != (hwaddr)-1) { 61aae9460eSPaul Brook /* Unregister previous mapping. */ 62e114feadSPeter Maydell memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory); 63ec3bb837SAvi Kivity } 64aae9460eSPaul Brook dev->mmio[n].addr = addr; 657feb640cSAlexey Korolev if (may_overlap) { 667feb640cSAlexey Korolev memory_region_add_subregion_overlap(get_system_memory(), 677feb640cSAlexey Korolev addr, 687feb640cSAlexey Korolev dev->mmio[n].memory, 697feb640cSAlexey Korolev priority); 707feb640cSAlexey Korolev } 717feb640cSAlexey Korolev else { 72ec3bb837SAvi Kivity memory_region_add_subregion(get_system_memory(), 73ec3bb837SAvi Kivity addr, 74ec3bb837SAvi Kivity dev->mmio[n].memory); 75aae9460eSPaul Brook } 767feb640cSAlexey Korolev } 77aae9460eSPaul Brook 787feb640cSAlexey Korolev void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) 797feb640cSAlexey Korolev { 807feb640cSAlexey Korolev sysbus_mmio_map_common(dev, n, addr, false, 0); 817feb640cSAlexey Korolev } 827feb640cSAlexey Korolev 837feb640cSAlexey Korolev void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, 847feb640cSAlexey Korolev unsigned priority) 857feb640cSAlexey Korolev { 867feb640cSAlexey Korolev sysbus_mmio_map_common(dev, n, addr, true, priority); 877feb640cSAlexey Korolev } 88aae9460eSPaul Brook 89aae9460eSPaul Brook /* Request an IRQ source. The actual IRQ object may be populated later. */ 90aae9460eSPaul Brook void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p) 91aae9460eSPaul Brook { 92aae9460eSPaul Brook int n; 93aae9460eSPaul Brook 94aae9460eSPaul Brook assert(dev->num_irq < QDEV_MAX_IRQ); 95aae9460eSPaul Brook n = dev->num_irq++; 96aae9460eSPaul Brook dev->irqp[n] = p; 97aae9460eSPaul Brook } 98aae9460eSPaul Brook 99aae9460eSPaul Brook /* Pass IRQs from a target device. */ 100aae9460eSPaul Brook void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target) 101aae9460eSPaul Brook { 102aae9460eSPaul Brook int i; 103aae9460eSPaul Brook assert(dev->num_irq == 0); 104aae9460eSPaul Brook dev->num_irq = target->num_irq; 105aae9460eSPaul Brook for (i = 0; i < dev->num_irq; i++) { 106aae9460eSPaul Brook dev->irqp[i] = target->irqp[i]; 107aae9460eSPaul Brook } 108aae9460eSPaul Brook } 109aae9460eSPaul Brook 110750ecd44SAvi Kivity void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory) 111ec3bb837SAvi Kivity { 112ec3bb837SAvi Kivity int n; 113ec3bb837SAvi Kivity 114ec3bb837SAvi Kivity assert(dev->num_mmio < QDEV_MAX_MMIO); 115ec3bb837SAvi Kivity n = dev->num_mmio++; 116ec3bb837SAvi Kivity dev->mmio[n].addr = -1; 117ec3bb837SAvi Kivity dev->mmio[n].memory = memory; 118ec3bb837SAvi Kivity } 119ec3bb837SAvi Kivity 12046c305efSPeter Maydell MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n) 12146c305efSPeter Maydell { 12246c305efSPeter Maydell return dev->mmio[n].memory; 12346c305efSPeter Maydell } 12446c305efSPeter Maydell 125c646f74fSGleb Natapov void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size) 126c646f74fSGleb Natapov { 127c646f74fSGleb Natapov pio_addr_t i; 128c646f74fSGleb Natapov 129c646f74fSGleb Natapov for (i = 0; i < size; i++) { 130c646f74fSGleb Natapov assert(dev->num_pio < QDEV_MAX_PIO); 131c646f74fSGleb Natapov dev->pio[dev->num_pio++] = ioport++; 132c646f74fSGleb Natapov } 133c646f74fSGleb Natapov } 134c646f74fSGleb Natapov 135d307af79SAnthony Liguori static int sysbus_device_init(DeviceState *dev) 136aae9460eSPaul Brook { 137999e12bbSAnthony Liguori SysBusDevice *sd = SYS_BUS_DEVICE(dev); 138999e12bbSAnthony Liguori SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd); 139aae9460eSPaul Brook 1404ce5dae8SPeter Maydell if (!sbc->init) { 1414ce5dae8SPeter Maydell return 0; 1424ce5dae8SPeter Maydell } 143999e12bbSAnthony Liguori return sbc->init(sd); 144aae9460eSPaul Brook } 145aae9460eSPaul Brook 146aae9460eSPaul Brook DeviceState *sysbus_create_varargs(const char *name, 147a8170e5eSAvi Kivity hwaddr addr, ...) 148aae9460eSPaul Brook { 149aae9460eSPaul Brook DeviceState *dev; 150aae9460eSPaul Brook SysBusDevice *s; 151aae9460eSPaul Brook va_list va; 152aae9460eSPaul Brook qemu_irq irq; 153aae9460eSPaul Brook int n; 154aae9460eSPaul Brook 155aae9460eSPaul Brook dev = qdev_create(NULL, name); 1561356b98dSAndreas Färber s = SYS_BUS_DEVICE(dev); 157e23a1b33SMarkus Armbruster qdev_init_nofail(dev); 158a8170e5eSAvi Kivity if (addr != (hwaddr)-1) { 159aae9460eSPaul Brook sysbus_mmio_map(s, 0, addr); 160aae9460eSPaul Brook } 161aae9460eSPaul Brook va_start(va, addr); 162aae9460eSPaul Brook n = 0; 163aae9460eSPaul Brook while (1) { 164aae9460eSPaul Brook irq = va_arg(va, qemu_irq); 165aae9460eSPaul Brook if (!irq) { 166aae9460eSPaul Brook break; 167aae9460eSPaul Brook } 168aae9460eSPaul Brook sysbus_connect_irq(s, n, irq); 169aae9460eSPaul Brook n++; 170aae9460eSPaul Brook } 171d0bc5bc3SMarkus Armbruster va_end(va); 172aae9460eSPaul Brook return dev; 173aae9460eSPaul Brook } 174cae4956eSGerd Hoffmann 1754912371fSBlue Swirl DeviceState *sysbus_try_create_varargs(const char *name, 176a8170e5eSAvi Kivity hwaddr addr, ...) 1774912371fSBlue Swirl { 1784912371fSBlue Swirl DeviceState *dev; 1794912371fSBlue Swirl SysBusDevice *s; 1804912371fSBlue Swirl va_list va; 1814912371fSBlue Swirl qemu_irq irq; 1824912371fSBlue Swirl int n; 1834912371fSBlue Swirl 1844912371fSBlue Swirl dev = qdev_try_create(NULL, name); 1854912371fSBlue Swirl if (!dev) { 1864912371fSBlue Swirl return NULL; 1874912371fSBlue Swirl } 1881356b98dSAndreas Färber s = SYS_BUS_DEVICE(dev); 1894912371fSBlue Swirl qdev_init_nofail(dev); 190a8170e5eSAvi Kivity if (addr != (hwaddr)-1) { 1914912371fSBlue Swirl sysbus_mmio_map(s, 0, addr); 1924912371fSBlue Swirl } 1934912371fSBlue Swirl va_start(va, addr); 1944912371fSBlue Swirl n = 0; 1954912371fSBlue Swirl while (1) { 1964912371fSBlue Swirl irq = va_arg(va, qemu_irq); 1974912371fSBlue Swirl if (!irq) { 1984912371fSBlue Swirl break; 1994912371fSBlue Swirl } 2004912371fSBlue Swirl sysbus_connect_irq(s, n, irq); 2014912371fSBlue Swirl n++; 2024912371fSBlue Swirl } 203d0bc5bc3SMarkus Armbruster va_end(va); 2044912371fSBlue Swirl return dev; 2054912371fSBlue Swirl } 2064912371fSBlue Swirl 20710c4c98aSGerd Hoffmann static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) 208cae4956eSGerd Hoffmann { 2091356b98dSAndreas Färber SysBusDevice *s = SYS_BUS_DEVICE(dev); 210a8170e5eSAvi Kivity hwaddr size; 211cae4956eSGerd Hoffmann int i; 212cae4956eSGerd Hoffmann 2130fba9fd6SDmitry Eremin-Solenikov monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq); 214cae4956eSGerd Hoffmann for (i = 0; i < s->num_mmio; i++) { 2153f7f1c80SAvi Kivity size = memory_region_size(s->mmio[i].memory); 216cae4956eSGerd Hoffmann monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", 2173f7f1c80SAvi Kivity indent, "", s->mmio[i].addr, size); 218cae4956eSGerd Hoffmann } 219cae4956eSGerd Hoffmann } 220c646f74fSGleb Natapov 221c646f74fSGleb Natapov static char *sysbus_get_fw_dev_path(DeviceState *dev) 222c646f74fSGleb Natapov { 2231356b98dSAndreas Färber SysBusDevice *s = SYS_BUS_DEVICE(dev); 224c646f74fSGleb Natapov char path[40]; 225c646f74fSGleb Natapov int off; 226c646f74fSGleb Natapov 227c646f74fSGleb Natapov off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev)); 228c646f74fSGleb Natapov 229c646f74fSGleb Natapov if (s->num_mmio) { 230c646f74fSGleb Natapov snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx, 231c646f74fSGleb Natapov s->mmio[0].addr); 232c646f74fSGleb Natapov } else if (s->num_pio) { 233c646f74fSGleb Natapov snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]); 234c646f74fSGleb Natapov } 235c646f74fSGleb Natapov 236a5cf8262SJim Meyering return g_strdup(path); 237c646f74fSGleb Natapov } 2382b985d9cSAvi Kivity 239a8170e5eSAvi Kivity void sysbus_add_io(SysBusDevice *dev, hwaddr addr, 2402b985d9cSAvi Kivity MemoryRegion *mem) 2412b985d9cSAvi Kivity { 2422b985d9cSAvi Kivity memory_region_add_subregion(get_system_io(), addr, mem); 2432b985d9cSAvi Kivity } 2442b985d9cSAvi Kivity 2452b985d9cSAvi Kivity void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem) 2462b985d9cSAvi Kivity { 2472b985d9cSAvi Kivity memory_region_del_subregion(get_system_io(), mem); 2482b985d9cSAvi Kivity } 24962ec4832SAvi Kivity 25062ec4832SAvi Kivity MemoryRegion *sysbus_address_space(SysBusDevice *dev) 25162ec4832SAvi Kivity { 25262ec4832SAvi Kivity return get_system_memory(); 25362ec4832SAvi Kivity } 254999e12bbSAnthony Liguori 25539bffca2SAnthony Liguori static void sysbus_device_class_init(ObjectClass *klass, void *data) 25639bffca2SAnthony Liguori { 25739bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 25839bffca2SAnthony Liguori k->init = sysbus_device_init; 2590d936928SAnthony Liguori k->bus_type = TYPE_SYSTEM_BUS; 26039bffca2SAnthony Liguori } 26139bffca2SAnthony Liguori 2628c43a6f0SAndreas Färber static const TypeInfo sysbus_device_type_info = { 263999e12bbSAnthony Liguori .name = TYPE_SYS_BUS_DEVICE, 264999e12bbSAnthony Liguori .parent = TYPE_DEVICE, 265999e12bbSAnthony Liguori .instance_size = sizeof(SysBusDevice), 266999e12bbSAnthony Liguori .abstract = true, 267999e12bbSAnthony Liguori .class_size = sizeof(SysBusDeviceClass), 26839bffca2SAnthony Liguori .class_init = sysbus_device_class_init, 269999e12bbSAnthony Liguori }; 270999e12bbSAnthony Liguori 2718185d216SPaolo Bonzini /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ 2728185d216SPaolo Bonzini static BusState *main_system_bus; 2738185d216SPaolo Bonzini 2748185d216SPaolo Bonzini static void main_system_bus_create(void) 2758185d216SPaolo Bonzini { 2768185d216SPaolo Bonzini /* assign main_system_bus before qbus_create_inplace() 2778185d216SPaolo Bonzini * in order to make "if (bus != sysbus_get_default())" work */ 2780d936928SAnthony Liguori main_system_bus = g_malloc0(system_bus_info.instance_size); 279*fb17dfe0SAndreas Färber qbus_create_inplace(main_system_bus, system_bus_info.instance_size, 280*fb17dfe0SAndreas Färber TYPE_SYSTEM_BUS, NULL, "main-system-bus"); 28164b625f4SPaolo Bonzini OBJECT(main_system_bus)->free = g_free; 282f968fc68SAnthony Liguori object_property_add_child(container_get(qdev_get_machine(), 283f968fc68SAnthony Liguori "/unattached"), 284f968fc68SAnthony Liguori "sysbus", OBJECT(main_system_bus), NULL); 2858185d216SPaolo Bonzini } 2868185d216SPaolo Bonzini 2878185d216SPaolo Bonzini BusState *sysbus_get_default(void) 2888185d216SPaolo Bonzini { 2898185d216SPaolo Bonzini if (!main_system_bus) { 2908185d216SPaolo Bonzini main_system_bus_create(); 2918185d216SPaolo Bonzini } 2928185d216SPaolo Bonzini return main_system_bus; 2938185d216SPaolo Bonzini } 2948185d216SPaolo Bonzini 29583f7d43aSAndreas Färber static void sysbus_register_types(void) 296999e12bbSAnthony Liguori { 2970d936928SAnthony Liguori type_register_static(&system_bus_info); 298999e12bbSAnthony Liguori type_register_static(&sysbus_device_type_info); 299999e12bbSAnthony Liguori } 300999e12bbSAnthony Liguori 30183f7d43aSAndreas Färber type_init(sysbus_register_types) 302