mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
61f3c91a67
There is no "version 2" of the "Lesser" General Public License. It is either "GPL version 2.0" or "Lesser GPL version 2.1". This patch replaces all occurrences of "Lesser GPL version 2" with "Lesser GPL version 2.1" in comment section. This patch contains all the files, whose maintainer I could not get from ‘get_maintainer.pl’ script. Signed-off-by: Chetan Pant <chetan4windows@gmail.com> Message-Id: <20201023124424.20177-1-chetan4windows@gmail.com> Reviewed-by: Thomas Huth <thuth@redhat.com> [thuth: Adapted exec.c and qdev-monitor.c to new location] Signed-off-by: Thomas Huth <thuth@redhat.com>
230 lines
6.6 KiB
C
230 lines
6.6 KiB
C
/*
|
|
* Platform Bus device to support dynamic Sysbus devices
|
|
*
|
|
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
|
*
|
|
* Author: Alexander Graf, <agraf@suse.de>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "hw/platform-bus.h"
|
|
#include "hw/qdev-properties.h"
|
|
#include "qapi/error.h"
|
|
#include "qemu/error-report.h"
|
|
#include "qemu/module.h"
|
|
|
|
|
|
/*
|
|
* Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
|
|
* the IRQ is not mapped on this Platform bus.
|
|
*/
|
|
int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|
int n)
|
|
{
|
|
qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
|
|
int i;
|
|
|
|
for (i = 0; i < pbus->num_irqs; i++) {
|
|
if (pbus->irqs[i] == sbirq) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
/* IRQ not mapped on platform bus */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
|
|
* -1 if the region is not mapped on this Platform bus.
|
|
*/
|
|
hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|
int n)
|
|
{
|
|
MemoryRegion *pbus_mr = &pbus->mmio;
|
|
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
|
Object *pbus_mr_obj = OBJECT(pbus_mr);
|
|
Object *parent_mr;
|
|
|
|
if (!memory_region_is_mapped(sbdev_mr)) {
|
|
/* Region is not mapped? */
|
|
return -1;
|
|
}
|
|
|
|
parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container",
|
|
&error_abort);
|
|
if (parent_mr != pbus_mr_obj) {
|
|
/* MMIO region is not mapped on platform bus */
|
|
return -1;
|
|
}
|
|
|
|
return object_property_get_uint(OBJECT(sbdev_mr), "addr", NULL);
|
|
}
|
|
|
|
static void platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
|
{
|
|
PlatformBusDevice *pbus = opaque;
|
|
qemu_irq sbirq;
|
|
int n, i;
|
|
|
|
for (n = 0; ; n++) {
|
|
if (!sysbus_has_irq(sbdev, n)) {
|
|
break;
|
|
}
|
|
|
|
sbirq = sysbus_get_connected_irq(sbdev, n);
|
|
for (i = 0; i < pbus->num_irqs; i++) {
|
|
if (pbus->irqs[i] == sbirq) {
|
|
bitmap_set(pbus->used_irqs, i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Loop through all sysbus devices and look for unassigned IRQ lines as well as
|
|
* unassociated MMIO regions. Connect them to the platform bus if available.
|
|
*/
|
|
static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
|
|
{
|
|
bitmap_zero(pbus->used_irqs, pbus->num_irqs);
|
|
foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
|
|
}
|
|
|
|
static void platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|
int n)
|
|
{
|
|
int max_irqs = pbus->num_irqs;
|
|
int irqn;
|
|
|
|
if (sysbus_is_irq_connected(sbdev, n)) {
|
|
/* IRQ is already mapped, nothing to do */
|
|
return;
|
|
}
|
|
|
|
irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
|
|
if (irqn >= max_irqs) {
|
|
error_report("Platform Bus: Can not fit IRQ line");
|
|
exit(1);
|
|
}
|
|
|
|
set_bit(irqn, pbus->used_irqs);
|
|
sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
|
|
}
|
|
|
|
static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|
int n)
|
|
{
|
|
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
|
uint64_t size = memory_region_size(sbdev_mr);
|
|
uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
|
|
uint64_t off;
|
|
bool found_region = false;
|
|
|
|
if (memory_region_is_mapped(sbdev_mr)) {
|
|
/* Region is already mapped, nothing to do */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Look for empty space in the MMIO space that is naturally aligned with
|
|
* the target device's memory region
|
|
*/
|
|
for (off = 0; off < pbus->mmio_size; off += alignment) {
|
|
if (!memory_region_find(&pbus->mmio, off, size).mr) {
|
|
found_region = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found_region) {
|
|
error_report("Platform Bus: Can not fit MMIO region of size %"PRIx64,
|
|
size);
|
|
exit(1);
|
|
}
|
|
|
|
/* Map the device's region into our Platform Bus MMIO space */
|
|
memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
|
|
}
|
|
|
|
/*
|
|
* Look for unassigned IRQ lines as well as unassociated MMIO regions.
|
|
* Connect them to the platform bus if available.
|
|
*/
|
|
void platform_bus_link_device(PlatformBusDevice *pbus, SysBusDevice *sbdev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; sysbus_has_irq(sbdev, i); i++) {
|
|
platform_bus_map_irq(pbus, sbdev, i);
|
|
}
|
|
|
|
for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
|
|
platform_bus_map_mmio(pbus, sbdev, i);
|
|
}
|
|
}
|
|
|
|
static void platform_bus_realize(DeviceState *dev, Error **errp)
|
|
{
|
|
PlatformBusDevice *pbus;
|
|
SysBusDevice *d;
|
|
int i;
|
|
|
|
d = SYS_BUS_DEVICE(dev);
|
|
pbus = PLATFORM_BUS_DEVICE(dev);
|
|
|
|
memory_region_init(&pbus->mmio, OBJECT(dev), "platform bus",
|
|
pbus->mmio_size);
|
|
sysbus_init_mmio(d, &pbus->mmio);
|
|
|
|
pbus->used_irqs = bitmap_new(pbus->num_irqs);
|
|
pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
|
|
for (i = 0; i < pbus->num_irqs; i++) {
|
|
sysbus_init_irq(d, &pbus->irqs[i]);
|
|
}
|
|
|
|
/* some devices might be initialized before so update used IRQs map */
|
|
plaform_bus_refresh_irqs(pbus);
|
|
}
|
|
|
|
static Property platform_bus_properties[] = {
|
|
DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
|
|
DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
|
|
DEFINE_PROP_END_OF_LIST()
|
|
};
|
|
|
|
static void platform_bus_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
dc->realize = platform_bus_realize;
|
|
device_class_set_props(dc, platform_bus_properties);
|
|
}
|
|
|
|
static const TypeInfo platform_bus_info = {
|
|
.name = TYPE_PLATFORM_BUS_DEVICE,
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
.instance_size = sizeof(PlatformBusDevice),
|
|
.class_init = platform_bus_class_init,
|
|
};
|
|
|
|
static void platform_bus_register_types(void)
|
|
{
|
|
type_register_static(&platform_bus_info);
|
|
}
|
|
|
|
type_init(platform_bus_register_types)
|