Statistics
| Branch: | Revision:

root / hw / sysbus.c @ 43997225

History | View | Annotate | Download (6.7 kB)

1
/*
2
 *  System (CPU) Bus device support code
3
 *
4
 *  Copyright (c) 2009 CodeSourcery
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * 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/>.
18
 */
19

    
20
#include "sysbus.h"
21
#include "monitor.h"
22
#include "exec-memory.h"
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
struct BusInfo system_bus_info = {
28
    .name       = "System",
29
    .size       = sizeof(BusState),
30
    .print_dev  = sysbus_dev_print,
31
    .get_fw_dev_path = sysbus_get_fw_dev_path,
32
};
33

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

    
43
void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
44
{
45
    assert(n >= 0 && n < dev->num_mmio);
46

    
47
    if (dev->mmio[n].addr == addr) {
48
        /* ??? region already mapped here.  */
49
        return;
50
    }
51
    if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
52
        /* Unregister previous mapping.  */
53
        memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
54
    }
55
    dev->mmio[n].addr = addr;
56
    memory_region_add_subregion(get_system_memory(),
57
                                addr,
58
                                dev->mmio[n].memory);
59
}
60

    
61

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

    
67
    assert(dev->num_irq < QDEV_MAX_IRQ);
68
    n = dev->num_irq++;
69
    dev->irqp[n] = p;
70
}
71

    
72
/* Pass IRQs from a target device.  */
73
void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
74
{
75
    int i;
76
    assert(dev->num_irq == 0);
77
    dev->num_irq = target->num_irq;
78
    for (i = 0; i < dev->num_irq; i++) {
79
        dev->irqp[i] = target->irqp[i];
80
    }
81
}
82

    
83
void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory)
84
{
85
    int n;
86

    
87
    assert(dev->num_mmio < QDEV_MAX_MMIO);
88
    n = dev->num_mmio++;
89
    dev->mmio[n].addr = -1;
90
    dev->mmio[n].memory = memory;
91
}
92

    
93
MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
94
{
95
    return dev->mmio[n].memory;
96
}
97

    
98
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
99
{
100
    pio_addr_t i;
101

    
102
    for (i = 0; i < size; i++) {
103
        assert(dev->num_pio < QDEV_MAX_PIO);
104
        dev->pio[dev->num_pio++] = ioport++;
105
    }
106
}
107

    
108
static int sysbus_device_init(DeviceState *dev)
109
{
110
    SysBusDevice *sd = SYS_BUS_DEVICE(dev);
111
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
112

    
113
    return sbc->init(sd);
114
}
115

    
116
DeviceState *sysbus_create_varargs(const char *name,
117
                                   target_phys_addr_t addr, ...)
118
{
119
    DeviceState *dev;
120
    SysBusDevice *s;
121
    va_list va;
122
    qemu_irq irq;
123
    int n;
124

    
125
    dev = qdev_create(NULL, name);
126
    s = sysbus_from_qdev(dev);
127
    qdev_init_nofail(dev);
128
    if (addr != (target_phys_addr_t)-1) {
129
        sysbus_mmio_map(s, 0, addr);
130
    }
131
    va_start(va, addr);
132
    n = 0;
133
    while (1) {
134
        irq = va_arg(va, qemu_irq);
135
        if (!irq) {
136
            break;
137
        }
138
        sysbus_connect_irq(s, n, irq);
139
        n++;
140
    }
141
    va_end(va);
142
    return dev;
143
}
144

    
145
DeviceState *sysbus_try_create_varargs(const char *name,
146
                                       target_phys_addr_t addr, ...)
147
{
148
    DeviceState *dev;
149
    SysBusDevice *s;
150
    va_list va;
151
    qemu_irq irq;
152
    int n;
153

    
154
    dev = qdev_try_create(NULL, name);
155
    if (!dev) {
156
        return NULL;
157
    }
158
    s = sysbus_from_qdev(dev);
159
    qdev_init_nofail(dev);
160
    if (addr != (target_phys_addr_t)-1) {
161
        sysbus_mmio_map(s, 0, addr);
162
    }
163
    va_start(va, addr);
164
    n = 0;
165
    while (1) {
166
        irq = va_arg(va, qemu_irq);
167
        if (!irq) {
168
            break;
169
        }
170
        sysbus_connect_irq(s, n, irq);
171
        n++;
172
    }
173
    va_end(va);
174
    return dev;
175
}
176

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

    
183
    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
184
    for (i = 0; i < s->num_mmio; i++) {
185
        size = memory_region_size(s->mmio[i].memory);
186
        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
187
                       indent, "", s->mmio[i].addr, size);
188
    }
189
}
190

    
191
static char *sysbus_get_fw_dev_path(DeviceState *dev)
192
{
193
    SysBusDevice *s = sysbus_from_qdev(dev);
194
    char path[40];
195
    int off;
196

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

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

    
206
    return strdup(path);
207
}
208

    
209
void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
210
                       MemoryRegion *mem)
211
{
212
    memory_region_add_subregion(get_system_memory(), addr, mem);
213
}
214

    
215
void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr,
216
                               MemoryRegion *mem, unsigned priority)
217
{
218
    memory_region_add_subregion_overlap(get_system_memory(), addr, mem,
219
                                        priority);
220
}
221

    
222
void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem)
223
{
224
    memory_region_del_subregion(get_system_memory(), mem);
225
}
226

    
227
void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
228
                       MemoryRegion *mem)
229
{
230
    memory_region_add_subregion(get_system_io(), addr, mem);
231
}
232

    
233
void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem)
234
{
235
    memory_region_del_subregion(get_system_io(), mem);
236
}
237

    
238
MemoryRegion *sysbus_address_space(SysBusDevice *dev)
239
{
240
    return get_system_memory();
241
}
242

    
243
static void sysbus_device_class_init(ObjectClass *klass, void *data)
244
{
245
    DeviceClass *k = DEVICE_CLASS(klass);
246
    k->init = sysbus_device_init;
247
    k->bus_info = &system_bus_info;
248
}
249

    
250
static TypeInfo sysbus_device_type_info = {
251
    .name = TYPE_SYS_BUS_DEVICE,
252
    .parent = TYPE_DEVICE,
253
    .instance_size = sizeof(SysBusDevice),
254
    .abstract = true,
255
    .class_size = sizeof(SysBusDeviceClass),
256
    .class_init = sysbus_device_class_init,
257
};
258

    
259
static void sysbus_register_types(void)
260
{
261
    type_register_static(&sysbus_device_type_info);
262
}
263

    
264
type_init(sysbus_register_types)