qemu/hw/core/platform-bus.c
<<
>>
Prefs
   1/*
   2 *  Platform Bus device to support dynamic Sysbus devices
   3 *
   4 * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
   5 *
   6 * Author: Alexander Graf, <agraf@suse.de>
   7 *
   8 * This library is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU Lesser General Public
  10 * License as published by the Free Software Foundation; either
  11 * version 2.1 of the License, or (at your option) any later version.
  12 *
  13 * This library is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * Lesser General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU Lesser General Public
  19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "hw/platform-bus.h"
  24#include "hw/qdev-properties.h"
  25#include "qapi/error.h"
  26#include "qemu/error-report.h"
  27#include "qemu/module.h"
  28
  29
  30/*
  31 * Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
  32 * the IRQ is not mapped on this Platform bus.
  33 */
  34int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
  35                          int n)
  36{
  37    qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
  38    int i;
  39
  40    for (i = 0; i < pbus->num_irqs; i++) {
  41        if (pbus->irqs[i] == sbirq) {
  42            return i;
  43        }
  44    }
  45
  46    /* IRQ not mapped on platform bus */
  47    return -1;
  48}
  49
  50/*
  51 * Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
  52 * -1 if the region is not mapped on this Platform bus.
  53 */
  54hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
  55                                  int n)
  56{
  57    MemoryRegion *pbus_mr = &pbus->mmio;
  58    MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
  59    Object *pbus_mr_obj = OBJECT(pbus_mr);
  60    Object *parent_mr;
  61
  62    if (!memory_region_is_mapped(sbdev_mr)) {
  63        /* Region is not mapped? */
  64        return -1;
  65    }
  66
  67    parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container",
  68                                         &error_abort);
  69    if (parent_mr != pbus_mr_obj) {
  70        /* MMIO region is not mapped on platform bus */
  71        return -1;
  72    }
  73
  74    return object_property_get_uint(OBJECT(sbdev_mr), "addr", NULL);
  75}
  76
  77static void platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
  78{
  79    PlatformBusDevice *pbus = opaque;
  80    qemu_irq sbirq;
  81    int n, i;
  82
  83    for (n = 0; ; n++) {
  84        if (!sysbus_has_irq(sbdev, n)) {
  85            break;
  86        }
  87
  88        sbirq = sysbus_get_connected_irq(sbdev, n);
  89        for (i = 0; i < pbus->num_irqs; i++) {
  90            if (pbus->irqs[i] == sbirq) {
  91                bitmap_set(pbus->used_irqs, i, 1);
  92                break;
  93            }
  94        }
  95    }
  96}
  97
  98/*
  99 * Loop through all sysbus devices and look for unassigned IRQ lines as well as
 100 * unassociated MMIO regions. Connect them to the platform bus if available.
 101 */
 102static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
 103{
 104    bitmap_zero(pbus->used_irqs, pbus->num_irqs);
 105    foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
 106}
 107
 108static void platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
 109                                 int n)
 110{
 111    int max_irqs = pbus->num_irqs;
 112    int irqn;
 113
 114    if (sysbus_is_irq_connected(sbdev, n)) {
 115        /* IRQ is already mapped, nothing to do */
 116        return;
 117    }
 118
 119    irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
 120    if (irqn >= max_irqs) {
 121        error_report("Platform Bus: Can not fit IRQ line");
 122        exit(1);
 123    }
 124
 125    set_bit(irqn, pbus->used_irqs);
 126    sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
 127}
 128
 129static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
 130                                  int n)
 131{
 132    MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
 133    uint64_t size = memory_region_size(sbdev_mr);
 134    uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
 135    uint64_t off;
 136    bool found_region = false;
 137
 138    if (memory_region_is_mapped(sbdev_mr)) {
 139        /* Region is already mapped, nothing to do */
 140        return;
 141    }
 142
 143    /*
 144     * Look for empty space in the MMIO space that is naturally aligned with
 145     * the target device's memory region
 146     */
 147    for (off = 0; off < pbus->mmio_size; off += alignment) {
 148        if (!memory_region_find(&pbus->mmio, off, size).mr) {
 149            found_region = true;
 150            break;
 151        }
 152    }
 153
 154    if (!found_region) {
 155        error_report("Platform Bus: Can not fit MMIO region of size %"PRIx64,
 156                     size);
 157        exit(1);
 158    }
 159
 160    /* Map the device's region into our Platform Bus MMIO space */
 161    memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
 162}
 163
 164/*
 165 * Look for unassigned IRQ lines as well as unassociated MMIO regions.
 166 * Connect them to the platform bus if available.
 167 */
 168void platform_bus_link_device(PlatformBusDevice *pbus, SysBusDevice *sbdev)
 169{
 170    int i;
 171
 172    for (i = 0; sysbus_has_irq(sbdev, i); i++) {
 173        platform_bus_map_irq(pbus, sbdev, i);
 174    }
 175
 176    for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
 177        platform_bus_map_mmio(pbus, sbdev, i);
 178    }
 179}
 180
 181static void platform_bus_realize(DeviceState *dev, Error **errp)
 182{
 183    PlatformBusDevice *pbus;
 184    SysBusDevice *d;
 185    int i;
 186
 187    d = SYS_BUS_DEVICE(dev);
 188    pbus = PLATFORM_BUS_DEVICE(dev);
 189
 190    memory_region_init(&pbus->mmio, OBJECT(dev), "platform bus",
 191                       pbus->mmio_size);
 192    sysbus_init_mmio(d, &pbus->mmio);
 193
 194    pbus->used_irqs = bitmap_new(pbus->num_irqs);
 195    pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
 196    for (i = 0; i < pbus->num_irqs; i++) {
 197        sysbus_init_irq(d, &pbus->irqs[i]);
 198    }
 199
 200    /* some devices might be initialized before so update used IRQs map */
 201    plaform_bus_refresh_irqs(pbus);
 202}
 203
 204static Property platform_bus_properties[] = {
 205    DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
 206    DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
 207    DEFINE_PROP_END_OF_LIST()
 208};
 209
 210static void platform_bus_class_init(ObjectClass *klass, void *data)
 211{
 212    DeviceClass *dc = DEVICE_CLASS(klass);
 213
 214    dc->realize = platform_bus_realize;
 215    device_class_set_props(dc, platform_bus_properties);
 216}
 217
 218static const TypeInfo platform_bus_info = {
 219    .name          = TYPE_PLATFORM_BUS_DEVICE,
 220    .parent        = TYPE_SYS_BUS_DEVICE,
 221    .instance_size = sizeof(PlatformBusDevice),
 222    .class_init    = platform_bus_class_init,
 223};
 224
 225static void platform_bus_register_types(void)
 226{
 227    type_register_static(&platform_bus_info);
 228}
 229
 230type_init(platform_bus_register_types)
 231