sysbus.c 5.4 KB
Newer Older
P
Paul Brook 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  System (CPU) Bus device support code
 *
 *  Copyright (c) 2009 CodeSourcery
 *
 * 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 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
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
P
Paul Brook 已提交
18 19 20 21
 */

#include "sysbus.h"
#include "sysemu.h"
22
#include "monitor.h"
P
Paul Brook 已提交
23

24
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
25
static char *sysbus_get_fw_dev_path(DeviceState *dev);
26 27 28 29 30

struct BusInfo system_bus_info = {
    .name       = "System",
    .size       = sizeof(BusState),
    .print_dev  = sysbus_dev_print,
31
    .get_fw_dev_path = sysbus_get_fw_dev_path,
32 33
};

P
Paul Brook 已提交
34 35 36
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
{
    assert(n >= 0 && n < dev->num_irq);
37
    dev->irqs[n] = NULL;
P
Paul Brook 已提交
38 39 40 41 42
    if (dev->irqp[n]) {
        *dev->irqp[n] = irq;
    }
}

A
Anthony Liguori 已提交
43
void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
P
Paul Brook 已提交
44 45 46 47 48 49 50
{
    assert(n >= 0 && n < dev->num_mmio);

    if (dev->mmio[n].addr == addr) {
        /* ??? region already mapped here.  */
        return;
    }
A
Anthony Liguori 已提交
51
    if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
P
Paul Brook 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
        /* Unregister previous mapping.  */
        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
                                     IO_MEM_UNASSIGNED);
    }
    dev->mmio[n].addr = addr;
    if (dev->mmio[n].cb) {
        dev->mmio[n].cb(dev, addr);
    } else {
        cpu_register_physical_memory(addr, dev->mmio[n].size,
                                     dev->mmio[n].iofunc);
    }
}


/* Request an IRQ source.  The actual IRQ object may be populated later.  */
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
{
    int n;

    assert(dev->num_irq < QDEV_MAX_IRQ);
    n = dev->num_irq++;
    dev->irqp[n] = p;
}

/* Pass IRQs from a target device.  */
void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
{
    int i;
    assert(dev->num_irq == 0);
    dev->num_irq = target->num_irq;
    for (i = 0; i < dev->num_irq; i++) {
        dev->irqp[i] = target->irqp[i];
    }
}

B
Blue Swirl 已提交
87 88
void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
                      ram_addr_t iofunc)
P
Paul Brook 已提交
89 90 91 92 93 94 95 96 97 98
{
    int n;

    assert(dev->num_mmio < QDEV_MAX_MMIO);
    n = dev->num_mmio++;
    dev->mmio[n].addr = -1;
    dev->mmio[n].size = size;
    dev->mmio[n].iofunc = iofunc;
}

A
Anthony Liguori 已提交
99
void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
P
Paul Brook 已提交
100 101 102 103 104 105 106 107 108 109 110
                         mmio_mapfunc cb)
{
    int n;

    assert(dev->num_mmio < QDEV_MAX_MMIO);
    n = dev->num_mmio++;
    dev->mmio[n].addr = -1;
    dev->mmio[n].size = size;
    dev->mmio[n].cb = cb;
}

111 112 113 114 115 116 117 118 119 120
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
{
    pio_addr_t i;

    for (i = 0; i < size; i++) {
        assert(dev->num_pio < QDEV_MAX_PIO);
        dev->pio[dev->num_pio++] = ioport++;
    }
}

121
static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
P
Paul Brook 已提交
122
{
P
Paul Brook 已提交
123
    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
P
Paul Brook 已提交
124

125
    return info->init(sysbus_from_qdev(dev));
P
Paul Brook 已提交
126 127
}

128
void sysbus_register_withprop(SysBusDeviceInfo *info)
P
Paul Brook 已提交
129
{
P
Paul Brook 已提交
130
    info->qdev.init = sysbus_device_init;
131
    info->qdev.bus_info = &system_bus_info;
P
Paul Brook 已提交
132

133 134
    assert(info->qdev.size >= sizeof(SysBusDevice));
    qdev_register(&info->qdev);
P
Paul Brook 已提交
135 136
}

P
Paul Brook 已提交
137 138 139 140 141
void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
{
    SysBusDeviceInfo *info;

    info = qemu_mallocz(sizeof(*info));
142 143
    info->qdev.name = qemu_strdup(name);
    info->qdev.size = size;
P
Paul Brook 已提交
144
    info->init = init;
145
    sysbus_register_withprop(info);
P
Paul Brook 已提交
146 147
}

P
Paul Brook 已提交
148
DeviceState *sysbus_create_varargs(const char *name,
A
Anthony Liguori 已提交
149
                                   target_phys_addr_t addr, ...)
P
Paul Brook 已提交
150 151 152 153 154 155 156 157 158
{
    DeviceState *dev;
    SysBusDevice *s;
    va_list va;
    qemu_irq irq;
    int n;

    dev = qdev_create(NULL, name);
    s = sysbus_from_qdev(dev);
M
Markus Armbruster 已提交
159
    qdev_init_nofail(dev);
A
Anthony Liguori 已提交
160
    if (addr != (target_phys_addr_t)-1) {
P
Paul Brook 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174
        sysbus_mmio_map(s, 0, addr);
    }
    va_start(va, addr);
    n = 0;
    while (1) {
        irq = va_arg(va, qemu_irq);
        if (!irq) {
            break;
        }
        sysbus_connect_irq(s, n, irq);
        n++;
    }
    return dev;
}
175

176
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
177 178 179 180
{
    SysBusDevice *s = sysbus_from_qdev(dev);
    int i;

181
    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
182 183 184 185 186
    for (i = 0; i < s->num_mmio; i++) {
        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
                       indent, "", s->mmio[i].addr, s->mmio[i].size);
    }
}
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

static char *sysbus_get_fw_dev_path(DeviceState *dev)
{
    SysBusDevice *s = sysbus_from_qdev(dev);
    char path[40];
    int off;

    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));

    if (s->num_mmio) {
        snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
                 s->mmio[0].addr);
    } else if (s->num_pio) {
        snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
    }

    return strdup(path);
}