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 { 44*b5917219SPeter Crosthwaite qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq); 45aae9460eSPaul Brook } 46aae9460eSPaul Brook 477feb640cSAlexey Korolev static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr, 48a1ff8ae0SMarcel Apfelbaum bool may_overlap, int priority) 49aae9460eSPaul Brook { 50aae9460eSPaul Brook assert(n >= 0 && n < dev->num_mmio); 51aae9460eSPaul Brook 52aae9460eSPaul Brook if (dev->mmio[n].addr == addr) { 53aae9460eSPaul Brook /* ??? region already mapped here. */ 54aae9460eSPaul Brook return; 55aae9460eSPaul Brook } 56a8170e5eSAvi Kivity if (dev->mmio[n].addr != (hwaddr)-1) { 57aae9460eSPaul Brook /* Unregister previous mapping. */ 58e114feadSPeter Maydell memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory); 59ec3bb837SAvi Kivity } 60aae9460eSPaul Brook dev->mmio[n].addr = addr; 617feb640cSAlexey Korolev if (may_overlap) { 627feb640cSAlexey Korolev memory_region_add_subregion_overlap(get_system_memory(), 637feb640cSAlexey Korolev addr, 647feb640cSAlexey Korolev dev->mmio[n].memory, 657feb640cSAlexey Korolev priority); 667feb640cSAlexey Korolev } 677feb640cSAlexey Korolev else { 68ec3bb837SAvi Kivity memory_region_add_subregion(get_system_memory(), 69ec3bb837SAvi Kivity addr, 70ec3bb837SAvi Kivity dev->mmio[n].memory); 71aae9460eSPaul Brook } 727feb640cSAlexey Korolev } 73aae9460eSPaul Brook 747feb640cSAlexey Korolev void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) 757feb640cSAlexey Korolev { 767feb640cSAlexey Korolev sysbus_mmio_map_common(dev, n, addr, false, 0); 777feb640cSAlexey Korolev } 787feb640cSAlexey Korolev 797feb640cSAlexey Korolev void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, 80a1ff8ae0SMarcel Apfelbaum int priority) 817feb640cSAlexey Korolev { 827feb640cSAlexey Korolev sysbus_mmio_map_common(dev, n, addr, true, priority); 837feb640cSAlexey Korolev } 84aae9460eSPaul Brook 85aae9460eSPaul Brook /* Request an IRQ source. The actual IRQ object may be populated later. */ 86aae9460eSPaul Brook void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p) 87aae9460eSPaul Brook { 88*b5917219SPeter Crosthwaite qdev_init_gpio_out_named(DEVICE(dev), p, SYSBUS_DEVICE_GPIO_IRQ, 1); 89aae9460eSPaul Brook } 90aae9460eSPaul Brook 91aae9460eSPaul Brook /* Pass IRQs from a target device. */ 92aae9460eSPaul Brook void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target) 93aae9460eSPaul Brook { 94*b5917219SPeter Crosthwaite qdev_pass_gpios(DEVICE(target), DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ); 95aae9460eSPaul Brook } 96aae9460eSPaul Brook 97750ecd44SAvi Kivity void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory) 98ec3bb837SAvi Kivity { 99ec3bb837SAvi Kivity int n; 100ec3bb837SAvi Kivity 101ec3bb837SAvi Kivity assert(dev->num_mmio < QDEV_MAX_MMIO); 102ec3bb837SAvi Kivity n = dev->num_mmio++; 103ec3bb837SAvi Kivity dev->mmio[n].addr = -1; 104ec3bb837SAvi Kivity dev->mmio[n].memory = memory; 105ec3bb837SAvi Kivity } 106ec3bb837SAvi Kivity 10746c305efSPeter Maydell MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n) 10846c305efSPeter Maydell { 10946c305efSPeter Maydell return dev->mmio[n].memory; 11046c305efSPeter Maydell } 11146c305efSPeter Maydell 112c646f74fSGleb Natapov void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size) 113c646f74fSGleb Natapov { 114c646f74fSGleb Natapov pio_addr_t i; 115c646f74fSGleb Natapov 116c646f74fSGleb Natapov for (i = 0; i < size; i++) { 117c646f74fSGleb Natapov assert(dev->num_pio < QDEV_MAX_PIO); 118c646f74fSGleb Natapov dev->pio[dev->num_pio++] = ioport++; 119c646f74fSGleb Natapov } 120c646f74fSGleb Natapov } 121c646f74fSGleb Natapov 122d307af79SAnthony Liguori static int sysbus_device_init(DeviceState *dev) 123aae9460eSPaul Brook { 124999e12bbSAnthony Liguori SysBusDevice *sd = SYS_BUS_DEVICE(dev); 125999e12bbSAnthony Liguori SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd); 126aae9460eSPaul Brook 1274ce5dae8SPeter Maydell if (!sbc->init) { 1284ce5dae8SPeter Maydell return 0; 1294ce5dae8SPeter Maydell } 130999e12bbSAnthony Liguori return sbc->init(sd); 131aae9460eSPaul Brook } 132aae9460eSPaul Brook 133aae9460eSPaul Brook DeviceState *sysbus_create_varargs(const char *name, 134a8170e5eSAvi Kivity hwaddr addr, ...) 135aae9460eSPaul Brook { 136aae9460eSPaul Brook DeviceState *dev; 137aae9460eSPaul Brook SysBusDevice *s; 138aae9460eSPaul Brook va_list va; 139aae9460eSPaul Brook qemu_irq irq; 140aae9460eSPaul Brook int n; 141aae9460eSPaul Brook 142aae9460eSPaul Brook dev = qdev_create(NULL, name); 1431356b98dSAndreas Färber s = SYS_BUS_DEVICE(dev); 144e23a1b33SMarkus Armbruster qdev_init_nofail(dev); 145a8170e5eSAvi Kivity if (addr != (hwaddr)-1) { 146aae9460eSPaul Brook sysbus_mmio_map(s, 0, addr); 147aae9460eSPaul Brook } 148aae9460eSPaul Brook va_start(va, addr); 149aae9460eSPaul Brook n = 0; 150aae9460eSPaul Brook while (1) { 151aae9460eSPaul Brook irq = va_arg(va, qemu_irq); 152aae9460eSPaul Brook if (!irq) { 153aae9460eSPaul Brook break; 154aae9460eSPaul Brook } 155aae9460eSPaul Brook sysbus_connect_irq(s, n, irq); 156aae9460eSPaul Brook n++; 157aae9460eSPaul Brook } 158d0bc5bc3SMarkus Armbruster va_end(va); 159aae9460eSPaul Brook return dev; 160aae9460eSPaul Brook } 161cae4956eSGerd Hoffmann 1624912371fSBlue Swirl DeviceState *sysbus_try_create_varargs(const char *name, 163a8170e5eSAvi Kivity hwaddr addr, ...) 1644912371fSBlue Swirl { 1654912371fSBlue Swirl DeviceState *dev; 1664912371fSBlue Swirl SysBusDevice *s; 1674912371fSBlue Swirl va_list va; 1684912371fSBlue Swirl qemu_irq irq; 1694912371fSBlue Swirl int n; 1704912371fSBlue Swirl 1714912371fSBlue Swirl dev = qdev_try_create(NULL, name); 1724912371fSBlue Swirl if (!dev) { 1734912371fSBlue Swirl return NULL; 1744912371fSBlue Swirl } 1751356b98dSAndreas Färber s = SYS_BUS_DEVICE(dev); 1764912371fSBlue Swirl qdev_init_nofail(dev); 177a8170e5eSAvi Kivity if (addr != (hwaddr)-1) { 1784912371fSBlue Swirl sysbus_mmio_map(s, 0, addr); 1794912371fSBlue Swirl } 1804912371fSBlue Swirl va_start(va, addr); 1814912371fSBlue Swirl n = 0; 1824912371fSBlue Swirl while (1) { 1834912371fSBlue Swirl irq = va_arg(va, qemu_irq); 1844912371fSBlue Swirl if (!irq) { 1854912371fSBlue Swirl break; 1864912371fSBlue Swirl } 1874912371fSBlue Swirl sysbus_connect_irq(s, n, irq); 1884912371fSBlue Swirl n++; 1894912371fSBlue Swirl } 190d0bc5bc3SMarkus Armbruster va_end(va); 1914912371fSBlue Swirl return dev; 1924912371fSBlue Swirl } 1934912371fSBlue Swirl 19410c4c98aSGerd Hoffmann static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) 195cae4956eSGerd Hoffmann { 1961356b98dSAndreas Färber SysBusDevice *s = SYS_BUS_DEVICE(dev); 197a8170e5eSAvi Kivity hwaddr size; 198cae4956eSGerd Hoffmann int i; 199cae4956eSGerd Hoffmann 200cae4956eSGerd Hoffmann for (i = 0; i < s->num_mmio; i++) { 2013f7f1c80SAvi Kivity size = memory_region_size(s->mmio[i].memory); 202cae4956eSGerd Hoffmann monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", 2033f7f1c80SAvi Kivity indent, "", s->mmio[i].addr, size); 204cae4956eSGerd Hoffmann } 205cae4956eSGerd Hoffmann } 206c646f74fSGleb Natapov 207c646f74fSGleb Natapov static char *sysbus_get_fw_dev_path(DeviceState *dev) 208c646f74fSGleb Natapov { 2091356b98dSAndreas Färber SysBusDevice *s = SYS_BUS_DEVICE(dev); 210c646f74fSGleb Natapov char path[40]; 211c646f74fSGleb Natapov int off; 212c646f74fSGleb Natapov 213c646f74fSGleb Natapov off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev)); 214c646f74fSGleb Natapov 215c646f74fSGleb Natapov if (s->num_mmio) { 216c646f74fSGleb Natapov snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx, 217c646f74fSGleb Natapov s->mmio[0].addr); 218c646f74fSGleb Natapov } else if (s->num_pio) { 219c646f74fSGleb Natapov snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]); 220c646f74fSGleb Natapov } 221c646f74fSGleb Natapov 222a5cf8262SJim Meyering return g_strdup(path); 223c646f74fSGleb Natapov } 2242b985d9cSAvi Kivity 225a8170e5eSAvi Kivity void sysbus_add_io(SysBusDevice *dev, hwaddr addr, 2262b985d9cSAvi Kivity MemoryRegion *mem) 2272b985d9cSAvi Kivity { 2282b985d9cSAvi Kivity memory_region_add_subregion(get_system_io(), addr, mem); 2292b985d9cSAvi Kivity } 2302b985d9cSAvi Kivity 23162ec4832SAvi Kivity MemoryRegion *sysbus_address_space(SysBusDevice *dev) 23262ec4832SAvi Kivity { 23362ec4832SAvi Kivity return get_system_memory(); 23462ec4832SAvi Kivity } 235999e12bbSAnthony Liguori 23639bffca2SAnthony Liguori static void sysbus_device_class_init(ObjectClass *klass, void *data) 23739bffca2SAnthony Liguori { 23839bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 23939bffca2SAnthony Liguori k->init = sysbus_device_init; 2400d936928SAnthony Liguori k->bus_type = TYPE_SYSTEM_BUS; 241837d3716SMarkus Armbruster /* 242837d3716SMarkus Armbruster * device_add plugs devices into suitable bus. For "real" buses, 243837d3716SMarkus Armbruster * that actually connects the device. For sysbus, the connections 244837d3716SMarkus Armbruster * need to be made separately, and device_add can't do that. The 245837d3716SMarkus Armbruster * device would be left unconnected, and could not possibly work. 246837d3716SMarkus Armbruster */ 247837d3716SMarkus Armbruster k->cannot_instantiate_with_device_add_yet = true; 24839bffca2SAnthony Liguori } 24939bffca2SAnthony Liguori 2508c43a6f0SAndreas Färber static const TypeInfo sysbus_device_type_info = { 251999e12bbSAnthony Liguori .name = TYPE_SYS_BUS_DEVICE, 252999e12bbSAnthony Liguori .parent = TYPE_DEVICE, 253999e12bbSAnthony Liguori .instance_size = sizeof(SysBusDevice), 254999e12bbSAnthony Liguori .abstract = true, 255999e12bbSAnthony Liguori .class_size = sizeof(SysBusDeviceClass), 25639bffca2SAnthony Liguori .class_init = sysbus_device_class_init, 257999e12bbSAnthony Liguori }; 258999e12bbSAnthony Liguori 2598185d216SPaolo Bonzini /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ 2608185d216SPaolo Bonzini static BusState *main_system_bus; 2618185d216SPaolo Bonzini 2628185d216SPaolo Bonzini static void main_system_bus_create(void) 2638185d216SPaolo Bonzini { 2648185d216SPaolo Bonzini /* assign main_system_bus before qbus_create_inplace() 2658185d216SPaolo Bonzini * in order to make "if (bus != sysbus_get_default())" work */ 2660d936928SAnthony Liguori main_system_bus = g_malloc0(system_bus_info.instance_size); 267fb17dfe0SAndreas Färber qbus_create_inplace(main_system_bus, system_bus_info.instance_size, 268fb17dfe0SAndreas Färber TYPE_SYSTEM_BUS, NULL, "main-system-bus"); 26964b625f4SPaolo Bonzini OBJECT(main_system_bus)->free = g_free; 270f968fc68SAnthony Liguori object_property_add_child(container_get(qdev_get_machine(), 271f968fc68SAnthony Liguori "/unattached"), 272f968fc68SAnthony Liguori "sysbus", OBJECT(main_system_bus), NULL); 2738185d216SPaolo Bonzini } 2748185d216SPaolo Bonzini 2758185d216SPaolo Bonzini BusState *sysbus_get_default(void) 2768185d216SPaolo Bonzini { 2778185d216SPaolo Bonzini if (!main_system_bus) { 2788185d216SPaolo Bonzini main_system_bus_create(); 2798185d216SPaolo Bonzini } 2808185d216SPaolo Bonzini return main_system_bus; 2818185d216SPaolo Bonzini } 2828185d216SPaolo Bonzini 28383f7d43aSAndreas Färber static void sysbus_register_types(void) 284999e12bbSAnthony Liguori { 2850d936928SAnthony Liguori type_register_static(&system_bus_info); 286999e12bbSAnthony Liguori type_register_static(&sysbus_device_type_info); 287999e12bbSAnthony Liguori } 288999e12bbSAnthony Liguori 28983f7d43aSAndreas Färber type_init(sysbus_register_types) 290