root / hw / s390x / virtio-ccw.c @ f24a6840
History | View | Annotate | Download (41.3 kB)
1 |
/*
|
---|---|
2 |
* virtio ccw target implementation
|
3 |
*
|
4 |
* Copyright 2012 IBM Corp.
|
5 |
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
6 |
*
|
7 |
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
8 |
* your option) any later version. See the COPYING file in the top-level
|
9 |
* directory.
|
10 |
*/
|
11 |
|
12 |
#include "hw/hw.h" |
13 |
#include "block/block.h" |
14 |
#include "sysemu/blockdev.h" |
15 |
#include "sysemu/sysemu.h" |
16 |
#include "net/net.h" |
17 |
#include "monitor/monitor.h" |
18 |
#include "hw/virtio/virtio.h" |
19 |
#include "hw/virtio/virtio-serial.h" |
20 |
#include "hw/virtio/virtio-net.h" |
21 |
#include "hw/sysbus.h" |
22 |
#include "qemu/bitops.h" |
23 |
#include "hw/virtio/virtio-bus.h" |
24 |
|
25 |
#include "ioinst.h" |
26 |
#include "css.h" |
27 |
#include "virtio-ccw.h" |
28 |
#include "trace.h" |
29 |
|
30 |
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, |
31 |
VirtioCcwDevice *dev); |
32 |
|
33 |
static int virtual_css_bus_reset(BusState *qbus) |
34 |
{ |
35 |
/* This should actually be modelled via the generic css */
|
36 |
css_reset(); |
37 |
|
38 |
/* we dont traverse ourself, return 0 */
|
39 |
return 0; |
40 |
} |
41 |
|
42 |
|
43 |
static void virtual_css_bus_class_init(ObjectClass *klass, void *data) |
44 |
{ |
45 |
BusClass *k = BUS_CLASS(klass); |
46 |
|
47 |
k->reset = virtual_css_bus_reset; |
48 |
} |
49 |
|
50 |
static const TypeInfo virtual_css_bus_info = { |
51 |
.name = TYPE_VIRTUAL_CSS_BUS, |
52 |
.parent = TYPE_BUS, |
53 |
.instance_size = sizeof(VirtualCssBus),
|
54 |
.class_init = virtual_css_bus_class_init, |
55 |
}; |
56 |
|
57 |
VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) |
58 |
{ |
59 |
VirtIODevice *vdev = NULL;
|
60 |
VirtioCcwDevice *dev = sch->driver_data; |
61 |
|
62 |
if (dev) {
|
63 |
vdev = virtio_bus_get_device(&dev->bus); |
64 |
} |
65 |
return vdev;
|
66 |
} |
67 |
|
68 |
static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, |
69 |
bool assign, bool set_handler) |
70 |
{ |
71 |
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); |
72 |
VirtQueue *vq = virtio_get_queue(vdev, n); |
73 |
EventNotifier *notifier = virtio_queue_get_host_notifier(vq); |
74 |
int r = 0; |
75 |
SubchDev *sch = dev->sch; |
76 |
uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;
|
77 |
|
78 |
if (assign) {
|
79 |
r = event_notifier_init(notifier, 1);
|
80 |
if (r < 0) { |
81 |
error_report("%s: unable to init event notifier: %d", __func__, r);
|
82 |
return r;
|
83 |
} |
84 |
virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
|
85 |
r = s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); |
86 |
if (r < 0) { |
87 |
error_report("%s: unable to assign ioeventfd: %d", __func__, r);
|
88 |
virtio_queue_set_host_notifier_fd_handler(vq, false, false); |
89 |
event_notifier_cleanup(notifier); |
90 |
return r;
|
91 |
} |
92 |
} else {
|
93 |
virtio_queue_set_host_notifier_fd_handler(vq, false, false); |
94 |
s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); |
95 |
event_notifier_cleanup(notifier); |
96 |
} |
97 |
return r;
|
98 |
} |
99 |
|
100 |
static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) |
101 |
{ |
102 |
VirtIODevice *vdev; |
103 |
int n, r;
|
104 |
|
105 |
if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
|
106 |
dev->ioeventfd_disabled || |
107 |
dev->ioeventfd_started) { |
108 |
return;
|
109 |
} |
110 |
vdev = virtio_bus_get_device(&dev->bus); |
111 |
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { |
112 |
if (!virtio_queue_get_num(vdev, n)) {
|
113 |
continue;
|
114 |
} |
115 |
r = virtio_ccw_set_guest2host_notifier(dev, n, true, true); |
116 |
if (r < 0) { |
117 |
goto assign_error;
|
118 |
} |
119 |
} |
120 |
dev->ioeventfd_started = true;
|
121 |
return;
|
122 |
|
123 |
assign_error:
|
124 |
while (--n >= 0) { |
125 |
if (!virtio_queue_get_num(vdev, n)) {
|
126 |
continue;
|
127 |
} |
128 |
r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); |
129 |
assert(r >= 0);
|
130 |
} |
131 |
dev->ioeventfd_started = false;
|
132 |
/* Disable ioeventfd for this device. */
|
133 |
dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; |
134 |
error_report("%s: failed. Fallback to userspace (slower).", __func__);
|
135 |
} |
136 |
|
137 |
static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) |
138 |
{ |
139 |
VirtIODevice *vdev; |
140 |
int n, r;
|
141 |
|
142 |
if (!dev->ioeventfd_started) {
|
143 |
return;
|
144 |
} |
145 |
vdev = virtio_bus_get_device(&dev->bus); |
146 |
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { |
147 |
if (!virtio_queue_get_num(vdev, n)) {
|
148 |
continue;
|
149 |
} |
150 |
r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); |
151 |
assert(r >= 0);
|
152 |
} |
153 |
dev->ioeventfd_started = false;
|
154 |
} |
155 |
|
156 |
VirtualCssBus *virtual_css_bus_init(void)
|
157 |
{ |
158 |
VirtualCssBus *cbus; |
159 |
BusState *bus; |
160 |
DeviceState *dev; |
161 |
|
162 |
/* Create bridge device */
|
163 |
dev = qdev_create(NULL, "virtual-css-bridge"); |
164 |
qdev_init_nofail(dev); |
165 |
|
166 |
/* Create bus on bridge device */
|
167 |
bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
|
168 |
cbus = VIRTUAL_CSS_BUS(bus); |
169 |
|
170 |
/* Enable hotplugging */
|
171 |
bus->allow_hotplug = 1;
|
172 |
|
173 |
return cbus;
|
174 |
} |
175 |
|
176 |
/* Communication blocks used by several channel commands. */
|
177 |
typedef struct VqInfoBlock { |
178 |
uint64_t queue; |
179 |
uint32_t align; |
180 |
uint16_t index; |
181 |
uint16_t num; |
182 |
} QEMU_PACKED VqInfoBlock; |
183 |
|
184 |
typedef struct VqConfigBlock { |
185 |
uint16_t index; |
186 |
uint16_t num_max; |
187 |
} QEMU_PACKED VqConfigBlock; |
188 |
|
189 |
typedef struct VirtioFeatDesc { |
190 |
uint32_t features; |
191 |
uint8_t index; |
192 |
} QEMU_PACKED VirtioFeatDesc; |
193 |
|
194 |
/* Specify where the virtqueues for the subchannel are in guest memory. */
|
195 |
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align, |
196 |
uint16_t index, uint16_t num) |
197 |
{ |
198 |
VirtIODevice *vdev = virtio_ccw_get_vdev(sch); |
199 |
|
200 |
if (index > VIRTIO_PCI_QUEUE_MAX) {
|
201 |
return -EINVAL;
|
202 |
} |
203 |
|
204 |
/* Current code in virtio.c relies on 4K alignment. */
|
205 |
if (addr && (align != 4096)) { |
206 |
return -EINVAL;
|
207 |
} |
208 |
|
209 |
if (!vdev) {
|
210 |
return -EINVAL;
|
211 |
} |
212 |
|
213 |
virtio_queue_set_addr(vdev, index, addr); |
214 |
if (!addr) {
|
215 |
virtio_queue_set_vector(vdev, index, 0);
|
216 |
} else {
|
217 |
/* Fail if we don't have a big enough queue. */
|
218 |
/* TODO: Add interface to handle vring.num changing */
|
219 |
if (virtio_queue_get_num(vdev, index) > num) {
|
220 |
return -EINVAL;
|
221 |
} |
222 |
virtio_queue_set_vector(vdev, index, index); |
223 |
} |
224 |
/* tell notify handler in case of config change */
|
225 |
vdev->config_vector = VIRTIO_PCI_QUEUE_MAX; |
226 |
return 0; |
227 |
} |
228 |
|
229 |
static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) |
230 |
{ |
231 |
int ret;
|
232 |
VqInfoBlock info; |
233 |
uint8_t status; |
234 |
VirtioFeatDesc features; |
235 |
void *config;
|
236 |
hwaddr indicators; |
237 |
VqConfigBlock vq_config; |
238 |
VirtioCcwDevice *dev = sch->driver_data; |
239 |
VirtIODevice *vdev = virtio_ccw_get_vdev(sch); |
240 |
bool check_len;
|
241 |
int len;
|
242 |
hwaddr hw_len; |
243 |
|
244 |
if (!dev) {
|
245 |
return -EINVAL;
|
246 |
} |
247 |
|
248 |
trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid, |
249 |
ccw.cmd_code); |
250 |
check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); |
251 |
|
252 |
/* Look at the command. */
|
253 |
switch (ccw.cmd_code) {
|
254 |
case CCW_CMD_SET_VQ:
|
255 |
if (check_len) {
|
256 |
if (ccw.count != sizeof(info)) { |
257 |
ret = -EINVAL; |
258 |
break;
|
259 |
} |
260 |
} else if (ccw.count < sizeof(info)) { |
261 |
/* Can't execute command. */
|
262 |
ret = -EINVAL; |
263 |
break;
|
264 |
} |
265 |
if (!ccw.cda) {
|
266 |
ret = -EFAULT; |
267 |
} else {
|
268 |
info.queue = ldq_phys(ccw.cda); |
269 |
info.align = ldl_phys(ccw.cda + sizeof(info.queue));
|
270 |
info.index = lduw_phys(ccw.cda + sizeof(info.queue)
|
271 |
+ sizeof(info.align));
|
272 |
info.num = lduw_phys(ccw.cda + sizeof(info.queue)
|
273 |
+ sizeof(info.align)
|
274 |
+ sizeof(info.index));
|
275 |
ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index, |
276 |
info.num); |
277 |
sch->curr_status.scsw.count = 0;
|
278 |
} |
279 |
break;
|
280 |
case CCW_CMD_VDEV_RESET:
|
281 |
virtio_ccw_stop_ioeventfd(dev); |
282 |
virtio_reset(vdev); |
283 |
ret = 0;
|
284 |
break;
|
285 |
case CCW_CMD_READ_FEAT:
|
286 |
if (check_len) {
|
287 |
if (ccw.count != sizeof(features)) { |
288 |
ret = -EINVAL; |
289 |
break;
|
290 |
} |
291 |
} else if (ccw.count < sizeof(features)) { |
292 |
/* Can't execute command. */
|
293 |
ret = -EINVAL; |
294 |
break;
|
295 |
} |
296 |
if (!ccw.cda) {
|
297 |
ret = -EFAULT; |
298 |
} else {
|
299 |
features.index = ldub_phys(ccw.cda + sizeof(features.features));
|
300 |
if (features.index < ARRAY_SIZE(dev->host_features)) {
|
301 |
features.features = dev->host_features[features.index]; |
302 |
} else {
|
303 |
/* Return zeroes if the guest supports more feature bits. */
|
304 |
features.features = 0;
|
305 |
} |
306 |
stl_le_phys(ccw.cda, features.features); |
307 |
sch->curr_status.scsw.count = ccw.count - sizeof(features);
|
308 |
ret = 0;
|
309 |
} |
310 |
break;
|
311 |
case CCW_CMD_WRITE_FEAT:
|
312 |
if (check_len) {
|
313 |
if (ccw.count != sizeof(features)) { |
314 |
ret = -EINVAL; |
315 |
break;
|
316 |
} |
317 |
} else if (ccw.count < sizeof(features)) { |
318 |
/* Can't execute command. */
|
319 |
ret = -EINVAL; |
320 |
break;
|
321 |
} |
322 |
if (!ccw.cda) {
|
323 |
ret = -EFAULT; |
324 |
} else {
|
325 |
features.index = ldub_phys(ccw.cda + sizeof(features.features));
|
326 |
features.features = ldl_le_phys(ccw.cda); |
327 |
if (features.index < ARRAY_SIZE(dev->host_features)) {
|
328 |
virtio_bus_set_vdev_features(&dev->bus, features.features); |
329 |
vdev->guest_features = features.features; |
330 |
} else {
|
331 |
/*
|
332 |
* If the guest supports more feature bits, assert that it
|
333 |
* passes us zeroes for those we don't support.
|
334 |
*/
|
335 |
if (features.features) {
|
336 |
fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
|
337 |
features.index, features.features); |
338 |
/* XXX: do a unit check here? */
|
339 |
} |
340 |
} |
341 |
sch->curr_status.scsw.count = ccw.count - sizeof(features);
|
342 |
ret = 0;
|
343 |
} |
344 |
break;
|
345 |
case CCW_CMD_READ_CONF:
|
346 |
if (check_len) {
|
347 |
if (ccw.count > vdev->config_len) {
|
348 |
ret = -EINVAL; |
349 |
break;
|
350 |
} |
351 |
} |
352 |
len = MIN(ccw.count, vdev->config_len); |
353 |
if (!ccw.cda) {
|
354 |
ret = -EFAULT; |
355 |
} else {
|
356 |
virtio_bus_get_vdev_config(&dev->bus, vdev->config); |
357 |
/* XXX config space endianness */
|
358 |
cpu_physical_memory_write(ccw.cda, vdev->config, len); |
359 |
sch->curr_status.scsw.count = ccw.count - len; |
360 |
ret = 0;
|
361 |
} |
362 |
break;
|
363 |
case CCW_CMD_WRITE_CONF:
|
364 |
if (check_len) {
|
365 |
if (ccw.count > vdev->config_len) {
|
366 |
ret = -EINVAL; |
367 |
break;
|
368 |
} |
369 |
} |
370 |
len = MIN(ccw.count, vdev->config_len); |
371 |
hw_len = len; |
372 |
if (!ccw.cda) {
|
373 |
ret = -EFAULT; |
374 |
} else {
|
375 |
config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
|
376 |
if (!config) {
|
377 |
ret = -EFAULT; |
378 |
} else {
|
379 |
len = hw_len; |
380 |
/* XXX config space endianness */
|
381 |
memcpy(vdev->config, config, len); |
382 |
cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
|
383 |
virtio_bus_set_vdev_config(&dev->bus, vdev->config); |
384 |
sch->curr_status.scsw.count = ccw.count - len; |
385 |
ret = 0;
|
386 |
} |
387 |
} |
388 |
break;
|
389 |
case CCW_CMD_WRITE_STATUS:
|
390 |
if (check_len) {
|
391 |
if (ccw.count != sizeof(status)) { |
392 |
ret = -EINVAL; |
393 |
break;
|
394 |
} |
395 |
} else if (ccw.count < sizeof(status)) { |
396 |
/* Can't execute command. */
|
397 |
ret = -EINVAL; |
398 |
break;
|
399 |
} |
400 |
if (!ccw.cda) {
|
401 |
ret = -EFAULT; |
402 |
} else {
|
403 |
status = ldub_phys(ccw.cda); |
404 |
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
405 |
virtio_ccw_stop_ioeventfd(dev); |
406 |
} |
407 |
virtio_set_status(vdev, status); |
408 |
if (vdev->status == 0) { |
409 |
virtio_reset(vdev); |
410 |
} |
411 |
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
412 |
virtio_ccw_start_ioeventfd(dev); |
413 |
} |
414 |
sch->curr_status.scsw.count = ccw.count - sizeof(status);
|
415 |
ret = 0;
|
416 |
} |
417 |
break;
|
418 |
case CCW_CMD_SET_IND:
|
419 |
if (check_len) {
|
420 |
if (ccw.count != sizeof(indicators)) { |
421 |
ret = -EINVAL; |
422 |
break;
|
423 |
} |
424 |
} else if (ccw.count < sizeof(indicators)) { |
425 |
/* Can't execute command. */
|
426 |
ret = -EINVAL; |
427 |
break;
|
428 |
} |
429 |
if (!ccw.cda) {
|
430 |
ret = -EFAULT; |
431 |
} else {
|
432 |
indicators = ldq_phys(ccw.cda); |
433 |
dev->indicators = indicators; |
434 |
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
|
435 |
ret = 0;
|
436 |
} |
437 |
break;
|
438 |
case CCW_CMD_SET_CONF_IND:
|
439 |
if (check_len) {
|
440 |
if (ccw.count != sizeof(indicators)) { |
441 |
ret = -EINVAL; |
442 |
break;
|
443 |
} |
444 |
} else if (ccw.count < sizeof(indicators)) { |
445 |
/* Can't execute command. */
|
446 |
ret = -EINVAL; |
447 |
break;
|
448 |
} |
449 |
if (!ccw.cda) {
|
450 |
ret = -EFAULT; |
451 |
} else {
|
452 |
indicators = ldq_phys(ccw.cda); |
453 |
dev->indicators2 = indicators; |
454 |
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
|
455 |
ret = 0;
|
456 |
} |
457 |
break;
|
458 |
case CCW_CMD_READ_VQ_CONF:
|
459 |
if (check_len) {
|
460 |
if (ccw.count != sizeof(vq_config)) { |
461 |
ret = -EINVAL; |
462 |
break;
|
463 |
} |
464 |
} else if (ccw.count < sizeof(vq_config)) { |
465 |
/* Can't execute command. */
|
466 |
ret = -EINVAL; |
467 |
break;
|
468 |
} |
469 |
if (!ccw.cda) {
|
470 |
ret = -EFAULT; |
471 |
} else {
|
472 |
vq_config.index = lduw_phys(ccw.cda); |
473 |
vq_config.num_max = virtio_queue_get_num(vdev, |
474 |
vq_config.index); |
475 |
stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max);
|
476 |
sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
|
477 |
ret = 0;
|
478 |
} |
479 |
break;
|
480 |
default:
|
481 |
ret = -ENOSYS; |
482 |
break;
|
483 |
} |
484 |
return ret;
|
485 |
} |
486 |
|
487 |
static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) |
488 |
{ |
489 |
unsigned int cssid = 0; |
490 |
unsigned int ssid = 0; |
491 |
unsigned int schid; |
492 |
unsigned int devno; |
493 |
bool have_devno = false; |
494 |
bool found = false; |
495 |
SubchDev *sch; |
496 |
int ret;
|
497 |
int num;
|
498 |
DeviceState *parent = DEVICE(dev); |
499 |
|
500 |
sch = g_malloc0(sizeof(SubchDev));
|
501 |
|
502 |
sch->driver_data = dev; |
503 |
dev->sch = sch; |
504 |
|
505 |
dev->indicators = 0;
|
506 |
|
507 |
/* Initialize subchannel structure. */
|
508 |
sch->channel_prog = 0x0;
|
509 |
sch->last_cmd_valid = false;
|
510 |
sch->orb = NULL;
|
511 |
/*
|
512 |
* Use a device number if provided. Otherwise, fall back to subchannel
|
513 |
* number.
|
514 |
*/
|
515 |
if (dev->bus_id) {
|
516 |
num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
|
517 |
if (num == 3) { |
518 |
if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
|
519 |
ret = -EINVAL; |
520 |
error_report("Invalid cssid or ssid: cssid %x, ssid %x",
|
521 |
cssid, ssid); |
522 |
goto out_err;
|
523 |
} |
524 |
/* Enforce use of virtual cssid. */
|
525 |
if (cssid != VIRTUAL_CSSID) {
|
526 |
ret = -EINVAL; |
527 |
error_report("cssid %x not valid for virtio devices", cssid);
|
528 |
goto out_err;
|
529 |
} |
530 |
if (css_devno_used(cssid, ssid, devno)) {
|
531 |
ret = -EEXIST; |
532 |
error_report("Device %x.%x.%04x already exists", cssid, ssid,
|
533 |
devno); |
534 |
goto out_err;
|
535 |
} |
536 |
sch->cssid = cssid; |
537 |
sch->ssid = ssid; |
538 |
sch->devno = devno; |
539 |
have_devno = true;
|
540 |
} else {
|
541 |
ret = -EINVAL; |
542 |
error_report("Malformed devno parameter '%s'", dev->bus_id);
|
543 |
goto out_err;
|
544 |
} |
545 |
} |
546 |
|
547 |
/* Find the next free id. */
|
548 |
if (have_devno) {
|
549 |
for (schid = 0; schid <= MAX_SCHID; schid++) { |
550 |
if (!css_find_subch(1, cssid, ssid, schid)) { |
551 |
sch->schid = schid; |
552 |
css_subch_assign(cssid, ssid, schid, devno, sch); |
553 |
found = true;
|
554 |
break;
|
555 |
} |
556 |
} |
557 |
if (!found) {
|
558 |
ret = -ENODEV; |
559 |
error_report("No free subchannel found for %x.%x.%04x", cssid, ssid,
|
560 |
devno); |
561 |
goto out_err;
|
562 |
} |
563 |
trace_virtio_ccw_new_device(cssid, ssid, schid, devno, |
564 |
"user-configured");
|
565 |
} else {
|
566 |
cssid = VIRTUAL_CSSID; |
567 |
for (ssid = 0; ssid <= MAX_SSID; ssid++) { |
568 |
for (schid = 0; schid <= MAX_SCHID; schid++) { |
569 |
if (!css_find_subch(1, cssid, ssid, schid)) { |
570 |
sch->cssid = cssid; |
571 |
sch->ssid = ssid; |
572 |
sch->schid = schid; |
573 |
devno = schid; |
574 |
/*
|
575 |
* If the devno is already taken, look further in this
|
576 |
* subchannel set.
|
577 |
*/
|
578 |
while (css_devno_used(cssid, ssid, devno)) {
|
579 |
if (devno == MAX_SCHID) {
|
580 |
devno = 0;
|
581 |
} else if (devno == schid - 1) { |
582 |
ret = -ENODEV; |
583 |
error_report("No free devno found");
|
584 |
goto out_err;
|
585 |
} else {
|
586 |
devno++; |
587 |
} |
588 |
} |
589 |
sch->devno = devno; |
590 |
css_subch_assign(cssid, ssid, schid, devno, sch); |
591 |
found = true;
|
592 |
break;
|
593 |
} |
594 |
} |
595 |
if (found) {
|
596 |
break;
|
597 |
} |
598 |
} |
599 |
if (!found) {
|
600 |
ret = -ENODEV; |
601 |
error_report("Virtual channel subsystem is full!");
|
602 |
goto out_err;
|
603 |
} |
604 |
trace_virtio_ccw_new_device(cssid, ssid, schid, devno, |
605 |
"auto-configured");
|
606 |
} |
607 |
|
608 |
/* Build initial schib. */
|
609 |
css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
|
610 |
|
611 |
sch->ccw_cb = virtio_ccw_cb; |
612 |
|
613 |
/* Build senseid data. */
|
614 |
memset(&sch->id, 0, sizeof(SenseId)); |
615 |
sch->id.reserved = 0xff;
|
616 |
sch->id.cu_type = VIRTIO_CCW_CU_TYPE; |
617 |
sch->id.cu_model = vdev->device_id; |
618 |
|
619 |
/* Only the first 32 feature bits are used. */
|
620 |
dev->host_features[0] = virtio_bus_get_vdev_features(&dev->bus,
|
621 |
dev->host_features[0]);
|
622 |
|
623 |
dev->host_features[0] |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; |
624 |
dev->host_features[0] |= 0x1 << VIRTIO_F_BAD_FEATURE; |
625 |
|
626 |
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, |
627 |
parent->hotplugged, 1);
|
628 |
return 0; |
629 |
|
630 |
out_err:
|
631 |
dev->sch = NULL;
|
632 |
g_free(sch); |
633 |
return ret;
|
634 |
} |
635 |
|
636 |
static int virtio_ccw_exit(VirtioCcwDevice *dev) |
637 |
{ |
638 |
SubchDev *sch = dev->sch; |
639 |
|
640 |
if (sch) {
|
641 |
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
642 |
g_free(sch); |
643 |
} |
644 |
dev->indicators = 0;
|
645 |
return 0; |
646 |
} |
647 |
|
648 |
static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev) |
649 |
{ |
650 |
DeviceState *qdev = DEVICE(ccw_dev); |
651 |
VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); |
652 |
DeviceState *vdev = DEVICE(&dev->vdev); |
653 |
|
654 |
virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
|
655 |
virtio_net_set_netclient_name(&dev->vdev, qdev->id, |
656 |
object_get_typename(OBJECT(qdev))); |
657 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
658 |
if (qdev_init(vdev) < 0) { |
659 |
return -1; |
660 |
} |
661 |
|
662 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
663 |
} |
664 |
|
665 |
static void virtio_ccw_net_instance_init(Object *obj) |
666 |
{ |
667 |
VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); |
668 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
669 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
670 |
} |
671 |
|
672 |
static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) |
673 |
{ |
674 |
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); |
675 |
DeviceState *vdev = DEVICE(&dev->vdev); |
676 |
virtio_blk_set_conf(vdev, &(dev->blk)); |
677 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
678 |
if (qdev_init(vdev) < 0) { |
679 |
return -1; |
680 |
} |
681 |
|
682 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
683 |
} |
684 |
|
685 |
static void virtio_ccw_blk_instance_init(Object *obj) |
686 |
{ |
687 |
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); |
688 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
|
689 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
690 |
} |
691 |
|
692 |
static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev) |
693 |
{ |
694 |
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev); |
695 |
DeviceState *vdev = DEVICE(&dev->vdev); |
696 |
DeviceState *proxy = DEVICE(ccw_dev); |
697 |
char *bus_name;
|
698 |
|
699 |
/*
|
700 |
* For command line compatibility, this sets the virtio-serial-device bus
|
701 |
* name as before.
|
702 |
*/
|
703 |
if (proxy->id) {
|
704 |
bus_name = g_strdup_printf("%s.0", proxy->id);
|
705 |
virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); |
706 |
g_free(bus_name); |
707 |
} |
708 |
|
709 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
710 |
if (qdev_init(vdev) < 0) { |
711 |
return -1; |
712 |
} |
713 |
|
714 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
715 |
} |
716 |
|
717 |
|
718 |
static void virtio_ccw_serial_instance_init(Object *obj) |
719 |
{ |
720 |
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); |
721 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
722 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
723 |
} |
724 |
|
725 |
static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev) |
726 |
{ |
727 |
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); |
728 |
DeviceState *vdev = DEVICE(&dev->vdev); |
729 |
|
730 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
731 |
if (qdev_init(vdev) < 0) { |
732 |
return -1; |
733 |
} |
734 |
|
735 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
736 |
} |
737 |
|
738 |
static void balloon_ccw_stats_get_all(Object *obj, struct Visitor *v, |
739 |
void *opaque, const char *name, |
740 |
Error **errp) |
741 |
{ |
742 |
VirtIOBalloonCcw *dev = opaque; |
743 |
object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
|
744 |
} |
745 |
|
746 |
static void balloon_ccw_stats_get_poll_interval(Object *obj, struct Visitor *v, |
747 |
void *opaque, const char *name, |
748 |
Error **errp) |
749 |
{ |
750 |
VirtIOBalloonCcw *dev = opaque; |
751 |
object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
|
752 |
errp); |
753 |
} |
754 |
|
755 |
static void balloon_ccw_stats_set_poll_interval(Object *obj, struct Visitor *v, |
756 |
void *opaque, const char *name, |
757 |
Error **errp) |
758 |
{ |
759 |
VirtIOBalloonCcw *dev = opaque; |
760 |
object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
|
761 |
errp); |
762 |
} |
763 |
|
764 |
static void virtio_ccw_balloon_instance_init(Object *obj) |
765 |
{ |
766 |
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj); |
767 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
|
768 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
769 |
|
770 |
object_property_add(obj, "guest-stats", "guest statistics", |
771 |
balloon_ccw_stats_get_all, NULL, NULL, dev, NULL); |
772 |
|
773 |
object_property_add(obj, "guest-stats-polling-interval", "int", |
774 |
balloon_ccw_stats_get_poll_interval, |
775 |
balloon_ccw_stats_set_poll_interval, |
776 |
NULL, dev, NULL); |
777 |
} |
778 |
|
779 |
static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev) |
780 |
{ |
781 |
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); |
782 |
DeviceState *vdev = DEVICE(&dev->vdev); |
783 |
DeviceState *qdev = DEVICE(ccw_dev); |
784 |
char *bus_name;
|
785 |
|
786 |
/*
|
787 |
* For command line compatibility, this sets the virtio-scsi-device bus
|
788 |
* name as before.
|
789 |
*/
|
790 |
if (qdev->id) {
|
791 |
bus_name = g_strdup_printf("%s.0", qdev->id);
|
792 |
virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); |
793 |
g_free(bus_name); |
794 |
} |
795 |
|
796 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
797 |
if (qdev_init(vdev) < 0) { |
798 |
return -1; |
799 |
} |
800 |
|
801 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
802 |
} |
803 |
|
804 |
static void virtio_ccw_scsi_instance_init(Object *obj) |
805 |
{ |
806 |
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); |
807 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
808 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
809 |
} |
810 |
|
811 |
#ifdef CONFIG_VHOST_SCSI
|
812 |
static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev) |
813 |
{ |
814 |
VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); |
815 |
DeviceState *vdev = DEVICE(&dev->vdev); |
816 |
|
817 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
818 |
if (qdev_init(vdev) < 0) { |
819 |
return -1; |
820 |
} |
821 |
|
822 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
823 |
} |
824 |
|
825 |
static void vhost_ccw_scsi_instance_init(Object *obj) |
826 |
{ |
827 |
VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); |
828 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
829 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
830 |
} |
831 |
#endif
|
832 |
|
833 |
static int virtio_ccw_rng_init(VirtioCcwDevice *ccw_dev) |
834 |
{ |
835 |
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev); |
836 |
DeviceState *vdev = DEVICE(&dev->vdev); |
837 |
|
838 |
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); |
839 |
if (qdev_init(vdev) < 0) { |
840 |
return -1; |
841 |
} |
842 |
|
843 |
object_property_set_link(OBJECT(dev), |
844 |
OBJECT(dev->vdev.conf.rng), "rng",
|
845 |
NULL);
|
846 |
|
847 |
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
848 |
} |
849 |
|
850 |
/* DeviceState to VirtioCcwDevice. Note: used on datapath,
|
851 |
* be careful and test performance if you change this.
|
852 |
*/
|
853 |
static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) |
854 |
{ |
855 |
return container_of(d, VirtioCcwDevice, parent_obj);
|
856 |
} |
857 |
|
858 |
static void virtio_ccw_notify(DeviceState *d, uint16_t vector) |
859 |
{ |
860 |
VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); |
861 |
SubchDev *sch = dev->sch; |
862 |
uint64_t indicators; |
863 |
|
864 |
if (vector >= 128) { |
865 |
return;
|
866 |
} |
867 |
|
868 |
if (vector < VIRTIO_PCI_QUEUE_MAX) {
|
869 |
if (!dev->indicators) {
|
870 |
return;
|
871 |
} |
872 |
indicators = ldq_phys(dev->indicators); |
873 |
indicators |= 1ULL << vector;
|
874 |
stq_phys(dev->indicators, indicators); |
875 |
} else {
|
876 |
if (!dev->indicators2) {
|
877 |
return;
|
878 |
} |
879 |
vector = 0;
|
880 |
indicators = ldq_phys(dev->indicators2); |
881 |
indicators |= 1ULL << vector;
|
882 |
stq_phys(dev->indicators2, indicators); |
883 |
} |
884 |
|
885 |
css_conditional_io_interrupt(sch); |
886 |
|
887 |
} |
888 |
|
889 |
static unsigned virtio_ccw_get_features(DeviceState *d) |
890 |
{ |
891 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
892 |
|
893 |
/* Only the first 32 feature bits are used. */
|
894 |
return dev->host_features[0]; |
895 |
} |
896 |
|
897 |
static void virtio_ccw_reset(DeviceState *d) |
898 |
{ |
899 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
900 |
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); |
901 |
|
902 |
virtio_ccw_stop_ioeventfd(dev); |
903 |
virtio_reset(vdev); |
904 |
css_reset_sch(dev->sch); |
905 |
dev->indicators = 0;
|
906 |
dev->indicators2 = 0;
|
907 |
} |
908 |
|
909 |
static void virtio_ccw_vmstate_change(DeviceState *d, bool running) |
910 |
{ |
911 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
912 |
|
913 |
if (running) {
|
914 |
virtio_ccw_start_ioeventfd(dev); |
915 |
} else {
|
916 |
virtio_ccw_stop_ioeventfd(dev); |
917 |
} |
918 |
} |
919 |
|
920 |
static bool virtio_ccw_query_guest_notifiers(DeviceState *d) |
921 |
{ |
922 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
923 |
|
924 |
return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA);
|
925 |
} |
926 |
|
927 |
static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) |
928 |
{ |
929 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
930 |
|
931 |
/* Stop using the generic ioeventfd, we are doing eventfd handling
|
932 |
* ourselves below */
|
933 |
dev->ioeventfd_disabled = assign; |
934 |
if (assign) {
|
935 |
virtio_ccw_stop_ioeventfd(dev); |
936 |
} |
937 |
return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); |
938 |
} |
939 |
|
940 |
static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, |
941 |
bool assign, bool with_irqfd) |
942 |
{ |
943 |
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); |
944 |
VirtQueue *vq = virtio_get_queue(vdev, n); |
945 |
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); |
946 |
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); |
947 |
|
948 |
if (assign) {
|
949 |
int r = event_notifier_init(notifier, 0); |
950 |
|
951 |
if (r < 0) { |
952 |
return r;
|
953 |
} |
954 |
virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
|
955 |
/* We do not support irqfd for classic I/O interrupts, because the
|
956 |
* classic interrupts are intermixed with the subchannel status, that
|
957 |
* is queried with test subchannel. We want to use vhost, though.
|
958 |
* Lets make sure to have vhost running and wire up the irq fd to
|
959 |
* land in qemu (and only the irq fd) in this code.
|
960 |
*/
|
961 |
if (k->guest_notifier_mask) {
|
962 |
k->guest_notifier_mask(vdev, n, false);
|
963 |
} |
964 |
/* get lost events and re-inject */
|
965 |
if (k->guest_notifier_pending &&
|
966 |
k->guest_notifier_pending(vdev, n)) { |
967 |
event_notifier_set(notifier); |
968 |
} |
969 |
} else {
|
970 |
if (k->guest_notifier_mask) {
|
971 |
k->guest_notifier_mask(vdev, n, true);
|
972 |
} |
973 |
virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
|
974 |
event_notifier_cleanup(notifier); |
975 |
} |
976 |
return 0; |
977 |
} |
978 |
|
979 |
static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, |
980 |
bool assigned)
|
981 |
{ |
982 |
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); |
983 |
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); |
984 |
int r, n;
|
985 |
|
986 |
for (n = 0; n < nvqs; n++) { |
987 |
if (!virtio_queue_get_num(vdev, n)) {
|
988 |
break;
|
989 |
} |
990 |
/* false -> true, as soon as irqfd works */
|
991 |
r = virtio_ccw_set_guest_notifier(dev, n, assigned, false);
|
992 |
if (r < 0) { |
993 |
goto assign_error;
|
994 |
} |
995 |
} |
996 |
return 0; |
997 |
|
998 |
assign_error:
|
999 |
while (--n >= 0) { |
1000 |
virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
|
1001 |
} |
1002 |
return r;
|
1003 |
} |
1004 |
|
1005 |
/**************** Virtio-ccw Bus Device Descriptions *******************/
|
1006 |
|
1007 |
static Property virtio_ccw_net_properties[] = {
|
1008 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1009 |
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
|
1010 |
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf), |
1011 |
DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf), |
1012 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1013 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1014 |
DEFINE_PROP_END_OF_LIST(), |
1015 |
}; |
1016 |
|
1017 |
static void virtio_ccw_net_class_init(ObjectClass *klass, void *data) |
1018 |
{ |
1019 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1020 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1021 |
|
1022 |
k->init = virtio_ccw_net_init; |
1023 |
k->exit = virtio_ccw_exit; |
1024 |
dc->reset = virtio_ccw_reset; |
1025 |
dc->props = virtio_ccw_net_properties; |
1026 |
} |
1027 |
|
1028 |
static const TypeInfo virtio_ccw_net = { |
1029 |
.name = TYPE_VIRTIO_NET_CCW, |
1030 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1031 |
.instance_size = sizeof(VirtIONetCcw),
|
1032 |
.instance_init = virtio_ccw_net_instance_init, |
1033 |
.class_init = virtio_ccw_net_class_init, |
1034 |
}; |
1035 |
|
1036 |
static Property virtio_ccw_blk_properties[] = {
|
1037 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1038 |
DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
|
1039 |
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk), |
1040 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1041 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1042 |
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
1043 |
DEFINE_PROP_BIT("x-data-plane", VirtIOBlkCcw, blk.data_plane, 0, false), |
1044 |
#endif
|
1045 |
DEFINE_PROP_END_OF_LIST(), |
1046 |
}; |
1047 |
|
1048 |
static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data) |
1049 |
{ |
1050 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1051 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1052 |
|
1053 |
k->init = virtio_ccw_blk_init; |
1054 |
k->exit = virtio_ccw_exit; |
1055 |
dc->reset = virtio_ccw_reset; |
1056 |
dc->props = virtio_ccw_blk_properties; |
1057 |
} |
1058 |
|
1059 |
static const TypeInfo virtio_ccw_blk = { |
1060 |
.name = TYPE_VIRTIO_BLK_CCW, |
1061 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1062 |
.instance_size = sizeof(VirtIOBlkCcw),
|
1063 |
.instance_init = virtio_ccw_blk_instance_init, |
1064 |
.class_init = virtio_ccw_blk_class_init, |
1065 |
}; |
1066 |
|
1067 |
static Property virtio_ccw_serial_properties[] = {
|
1068 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1069 |
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial), |
1070 |
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
|
1071 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1072 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1073 |
DEFINE_PROP_END_OF_LIST(), |
1074 |
}; |
1075 |
|
1076 |
static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data) |
1077 |
{ |
1078 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1079 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1080 |
|
1081 |
k->init = virtio_ccw_serial_init; |
1082 |
k->exit = virtio_ccw_exit; |
1083 |
dc->reset = virtio_ccw_reset; |
1084 |
dc->props = virtio_ccw_serial_properties; |
1085 |
} |
1086 |
|
1087 |
static const TypeInfo virtio_ccw_serial = { |
1088 |
.name = TYPE_VIRTIO_SERIAL_CCW, |
1089 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1090 |
.instance_size = sizeof(VirtioSerialCcw),
|
1091 |
.instance_init = virtio_ccw_serial_instance_init, |
1092 |
.class_init = virtio_ccw_serial_class_init, |
1093 |
}; |
1094 |
|
1095 |
static Property virtio_ccw_balloon_properties[] = {
|
1096 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1097 |
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
|
1098 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1099 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1100 |
DEFINE_PROP_END_OF_LIST(), |
1101 |
}; |
1102 |
|
1103 |
static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data) |
1104 |
{ |
1105 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1106 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1107 |
|
1108 |
k->init = virtio_ccw_balloon_init; |
1109 |
k->exit = virtio_ccw_exit; |
1110 |
dc->reset = virtio_ccw_reset; |
1111 |
dc->props = virtio_ccw_balloon_properties; |
1112 |
} |
1113 |
|
1114 |
static const TypeInfo virtio_ccw_balloon = { |
1115 |
.name = TYPE_VIRTIO_BALLOON_CCW, |
1116 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1117 |
.instance_size = sizeof(VirtIOBalloonCcw),
|
1118 |
.instance_init = virtio_ccw_balloon_instance_init, |
1119 |
.class_init = virtio_ccw_balloon_class_init, |
1120 |
}; |
1121 |
|
1122 |
static Property virtio_ccw_scsi_properties[] = {
|
1123 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1124 |
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf), |
1125 |
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
|
1126 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1127 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1128 |
DEFINE_PROP_END_OF_LIST(), |
1129 |
}; |
1130 |
|
1131 |
static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data) |
1132 |
{ |
1133 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1134 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1135 |
|
1136 |
k->init = virtio_ccw_scsi_init; |
1137 |
k->exit = virtio_ccw_exit; |
1138 |
dc->reset = virtio_ccw_reset; |
1139 |
dc->props = virtio_ccw_scsi_properties; |
1140 |
} |
1141 |
|
1142 |
static const TypeInfo virtio_ccw_scsi = { |
1143 |
.name = TYPE_VIRTIO_SCSI_CCW, |
1144 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1145 |
.instance_size = sizeof(VirtIOSCSICcw),
|
1146 |
.instance_init = virtio_ccw_scsi_instance_init, |
1147 |
.class_init = virtio_ccw_scsi_class_init, |
1148 |
}; |
1149 |
|
1150 |
#ifdef CONFIG_VHOST_SCSI
|
1151 |
static Property vhost_ccw_scsi_properties[] = {
|
1152 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1153 |
DEFINE_VHOST_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf), |
1154 |
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
|
1155 |
DEFINE_PROP_END_OF_LIST(), |
1156 |
}; |
1157 |
|
1158 |
static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) |
1159 |
{ |
1160 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1161 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1162 |
|
1163 |
k->init = vhost_ccw_scsi_init; |
1164 |
k->exit = virtio_ccw_exit; |
1165 |
dc->reset = virtio_ccw_reset; |
1166 |
dc->props = vhost_ccw_scsi_properties; |
1167 |
} |
1168 |
|
1169 |
static const TypeInfo vhost_ccw_scsi = { |
1170 |
.name = TYPE_VHOST_SCSI_CCW, |
1171 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1172 |
.instance_size = sizeof(VirtIOSCSICcw),
|
1173 |
.instance_init = vhost_ccw_scsi_instance_init, |
1174 |
.class_init = vhost_ccw_scsi_class_init, |
1175 |
}; |
1176 |
#endif
|
1177 |
|
1178 |
static void virtio_ccw_rng_instance_init(Object *obj) |
1179 |
{ |
1180 |
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); |
1181 |
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
1182 |
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); |
1183 |
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
1184 |
(Object **)&dev->vdev.conf.rng, NULL);
|
1185 |
} |
1186 |
|
1187 |
static Property virtio_ccw_rng_properties[] = {
|
1188 |
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
1189 |
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
|
1190 |
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf), |
1191 |
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
1192 |
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
1193 |
DEFINE_PROP_END_OF_LIST(), |
1194 |
}; |
1195 |
|
1196 |
static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data) |
1197 |
{ |
1198 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1199 |
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); |
1200 |
|
1201 |
k->init = virtio_ccw_rng_init; |
1202 |
k->exit = virtio_ccw_exit; |
1203 |
dc->reset = virtio_ccw_reset; |
1204 |
dc->props = virtio_ccw_rng_properties; |
1205 |
} |
1206 |
|
1207 |
static const TypeInfo virtio_ccw_rng = { |
1208 |
.name = TYPE_VIRTIO_RNG_CCW, |
1209 |
.parent = TYPE_VIRTIO_CCW_DEVICE, |
1210 |
.instance_size = sizeof(VirtIORNGCcw),
|
1211 |
.instance_init = virtio_ccw_rng_instance_init, |
1212 |
.class_init = virtio_ccw_rng_class_init, |
1213 |
}; |
1214 |
|
1215 |
static int virtio_ccw_busdev_init(DeviceState *dev) |
1216 |
{ |
1217 |
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; |
1218 |
VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); |
1219 |
|
1220 |
virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
|
1221 |
|
1222 |
return _info->init(_dev);
|
1223 |
} |
1224 |
|
1225 |
static int virtio_ccw_busdev_exit(DeviceState *dev) |
1226 |
{ |
1227 |
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; |
1228 |
VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); |
1229 |
|
1230 |
return _info->exit(_dev);
|
1231 |
} |
1232 |
|
1233 |
static int virtio_ccw_busdev_unplug(DeviceState *dev) |
1234 |
{ |
1235 |
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; |
1236 |
SubchDev *sch = _dev->sch; |
1237 |
|
1238 |
virtio_ccw_stop_ioeventfd(_dev); |
1239 |
|
1240 |
/*
|
1241 |
* We should arrive here only for device_del, since we don't support
|
1242 |
* direct hot(un)plug of channels, but only through virtio.
|
1243 |
*/
|
1244 |
assert(sch != NULL);
|
1245 |
/* Subchannel is now disabled and no longer valid. */
|
1246 |
sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | |
1247 |
PMCW_FLAGS_MASK_DNV); |
1248 |
|
1249 |
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); |
1250 |
|
1251 |
object_unparent(OBJECT(dev)); |
1252 |
return 0; |
1253 |
} |
1254 |
|
1255 |
static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) |
1256 |
{ |
1257 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1258 |
|
1259 |
dc->init = virtio_ccw_busdev_init; |
1260 |
dc->exit = virtio_ccw_busdev_exit; |
1261 |
dc->unplug = virtio_ccw_busdev_unplug; |
1262 |
dc->bus_type = TYPE_VIRTUAL_CSS_BUS; |
1263 |
|
1264 |
} |
1265 |
|
1266 |
static const TypeInfo virtio_ccw_device_info = { |
1267 |
.name = TYPE_VIRTIO_CCW_DEVICE, |
1268 |
.parent = TYPE_DEVICE, |
1269 |
.instance_size = sizeof(VirtioCcwDevice),
|
1270 |
.class_init = virtio_ccw_device_class_init, |
1271 |
.class_size = sizeof(VirtIOCCWDeviceClass),
|
1272 |
.abstract = true,
|
1273 |
}; |
1274 |
|
1275 |
/***************** Virtual-css Bus Bridge Device ********************/
|
1276 |
/* Only required to have the virtio bus as child in the system bus */
|
1277 |
|
1278 |
static int virtual_css_bridge_init(SysBusDevice *dev) |
1279 |
{ |
1280 |
/* nothing */
|
1281 |
return 0; |
1282 |
} |
1283 |
|
1284 |
static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) |
1285 |
{ |
1286 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1287 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
1288 |
|
1289 |
k->init = virtual_css_bridge_init; |
1290 |
dc->no_user = 1;
|
1291 |
} |
1292 |
|
1293 |
static const TypeInfo virtual_css_bridge_info = { |
1294 |
.name = "virtual-css-bridge",
|
1295 |
.parent = TYPE_SYS_BUS_DEVICE, |
1296 |
.instance_size = sizeof(SysBusDevice),
|
1297 |
.class_init = virtual_css_bridge_class_init, |
1298 |
}; |
1299 |
|
1300 |
/* virtio-ccw-bus */
|
1301 |
|
1302 |
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, |
1303 |
VirtioCcwDevice *dev) |
1304 |
{ |
1305 |
DeviceState *qdev = DEVICE(dev); |
1306 |
BusState *qbus; |
1307 |
char virtio_bus_name[] = "virtio-bus"; |
1308 |
|
1309 |
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS, |
1310 |
qdev, virtio_bus_name); |
1311 |
qbus = BUS(bus); |
1312 |
qbus->allow_hotplug = 1;
|
1313 |
} |
1314 |
|
1315 |
static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) |
1316 |
{ |
1317 |
VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); |
1318 |
BusClass *bus_class = BUS_CLASS(klass); |
1319 |
|
1320 |
bus_class->max_dev = 1;
|
1321 |
k->notify = virtio_ccw_notify; |
1322 |
k->get_features = virtio_ccw_get_features; |
1323 |
k->vmstate_change = virtio_ccw_vmstate_change; |
1324 |
k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; |
1325 |
k->set_host_notifier = virtio_ccw_set_host_notifier; |
1326 |
k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; |
1327 |
} |
1328 |
|
1329 |
static const TypeInfo virtio_ccw_bus_info = { |
1330 |
.name = TYPE_VIRTIO_CCW_BUS, |
1331 |
.parent = TYPE_VIRTIO_BUS, |
1332 |
.instance_size = sizeof(VirtioCcwBusState),
|
1333 |
.class_init = virtio_ccw_bus_class_init, |
1334 |
}; |
1335 |
|
1336 |
static void virtio_ccw_register(void) |
1337 |
{ |
1338 |
type_register_static(&virtio_ccw_bus_info); |
1339 |
type_register_static(&virtual_css_bus_info); |
1340 |
type_register_static(&virtio_ccw_device_info); |
1341 |
type_register_static(&virtio_ccw_serial); |
1342 |
type_register_static(&virtio_ccw_blk); |
1343 |
type_register_static(&virtio_ccw_net); |
1344 |
type_register_static(&virtio_ccw_balloon); |
1345 |
type_register_static(&virtio_ccw_scsi); |
1346 |
#ifdef CONFIG_VHOST_SCSI
|
1347 |
type_register_static(&vhost_ccw_scsi); |
1348 |
#endif
|
1349 |
type_register_static(&virtio_ccw_rng); |
1350 |
type_register_static(&virtual_css_bridge_info); |
1351 |
} |
1352 |
|
1353 |
type_init(virtio_ccw_register) |