Statistics
| Branch: | Revision:

root / hw / spapr_vio.c @ 4040ab72

History | View | Annotate | Download (4.9 kB)

1
/*
2
 * QEMU sPAPR VIO code
3
 *
4
 * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
5
 * Based on the s390 virtio bus code:
6
 * Copyright (c) 2009 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 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 "hw.h"
23
#include "sysemu.h"
24
#include "boards.h"
25
#include "monitor.h"
26
#include "loader.h"
27
#include "elf.h"
28
#include "hw/sysbus.h"
29
#include "kvm.h"
30
#include "device_tree.h"
31

    
32
#include "hw/spapr.h"
33
#include "hw/spapr_vio.h"
34

    
35
#ifdef CONFIG_FDT
36
#include <libfdt.h>
37
#endif /* CONFIG_FDT */
38

    
39
/* #define DEBUG_SPAPR */
40

    
41
#ifdef DEBUG_SPAPR
42
#define dprintf(fmt, ...) \
43
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
44
#else
45
#define dprintf(fmt, ...) \
46
    do { } while (0)
47
#endif
48

    
49
static struct BusInfo spapr_vio_bus_info = {
50
    .name       = "spapr-vio",
51
    .size       = sizeof(VIOsPAPRBus),
52
};
53

    
54
VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
55
{
56
    DeviceState *qdev;
57
    VIOsPAPRDevice *dev = NULL;
58

    
59
    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
60
        dev = (VIOsPAPRDevice *)qdev;
61
        if (dev->reg == reg) {
62
            break;
63
        }
64
    }
65

    
66
    return dev;
67
}
68

    
69
#ifdef CONFIG_FDT
70
static int vio_make_devnode(VIOsPAPRDevice *dev,
71
                            void *fdt)
72
{
73
    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
74
    int vdevice_off, node_off;
75
    int ret;
76

    
77
    vdevice_off = fdt_path_offset(fdt, "/vdevice");
78
    if (vdevice_off < 0) {
79
        return vdevice_off;
80
    }
81

    
82
    node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
83
    if (node_off < 0) {
84
        return node_off;
85
    }
86

    
87
    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
88
    if (ret < 0) {
89
        return ret;
90
    }
91

    
92
    if (info->dt_type) {
93
        ret = fdt_setprop_string(fdt, node_off, "device_type",
94
                                 info->dt_type);
95
        if (ret < 0) {
96
            return ret;
97
        }
98
    }
99

    
100
    if (info->dt_compatible) {
101
        ret = fdt_setprop_string(fdt, node_off, "compatible",
102
                                 info->dt_compatible);
103
        if (ret < 0) {
104
            return ret;
105
        }
106
    }
107

    
108
    if (info->devnode) {
109
        ret = (info->devnode)(dev, fdt, node_off);
110
        if (ret < 0) {
111
            return ret;
112
        }
113
    }
114

    
115
    return node_off;
116
}
117
#endif /* CONFIG_FDT */
118

    
119
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
120
{
121
    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
122
    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
123
    char *id;
124

    
125
    if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
126
        return -1;
127
    }
128

    
129
    dev->qdev.id = id;
130

    
131
    return info->init(dev);
132
}
133

    
134
void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
135
{
136
    info->qdev.init = spapr_vio_busdev_init;
137
    info->qdev.bus_info = &spapr_vio_bus_info;
138

    
139
    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
140
    qdev_register(&info->qdev);
141
}
142

    
143
VIOsPAPRBus *spapr_vio_bus_init(void)
144
{
145
    VIOsPAPRBus *bus;
146
    BusState *qbus;
147
    DeviceState *dev;
148
    DeviceInfo *qinfo;
149

    
150
    /* Create bridge device */
151
    dev = qdev_create(NULL, "spapr-vio-bridge");
152
    qdev_init_nofail(dev);
153

    
154
    /* Create bus on bridge device */
155

    
156
    qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
157
    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
158

    
159
    for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
160
        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
161

    
162
        if (qinfo->bus_info != &spapr_vio_bus_info) {
163
            continue;
164
        }
165

    
166
        if (info->hcalls) {
167
            info->hcalls(bus);
168
        }
169
    }
170

    
171
    return bus;
172
}
173

    
174
/* Represents sPAPR hcall VIO devices */
175

    
176
static int spapr_vio_bridge_init(SysBusDevice *dev)
177
{
178
    /* nothing */
179
    return 0;
180
}
181

    
182
static SysBusDeviceInfo spapr_vio_bridge_info = {
183
    .init = spapr_vio_bridge_init,
184
    .qdev.name  = "spapr-vio-bridge",
185
    .qdev.size  = sizeof(SysBusDevice),
186
    .qdev.no_user = 1,
187
};
188

    
189
static void spapr_vio_register_devices(void)
190
{
191
    sysbus_register_withprop(&spapr_vio_bridge_info);
192
}
193

    
194
device_init(spapr_vio_register_devices)
195

    
196
#ifdef CONFIG_FDT
197
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
198
{
199
    DeviceState *qdev;
200
    int ret = 0;
201

    
202
    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
203
        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
204

    
205
        ret = vio_make_devnode(dev, fdt);
206

    
207
        if (ret < 0) {
208
            return ret;
209
        }
210
    }
211

    
212
    return 0;
213
}
214
#endif /* CONFIG_FDT */