Revision b45d63b6 hw/spapr_vio.c
b/hw/spapr_vio.c | ||
---|---|---|
28 | 28 |
#include "hw/sysbus.h" |
29 | 29 |
#include "kvm.h" |
30 | 30 |
#include "device_tree.h" |
31 |
#include "kvm_ppc.h" |
|
31 | 32 |
|
32 | 33 |
#include "hw/spapr.h" |
33 | 34 |
#include "hw/spapr_vio.h" |
... | ... | |
359 | 360 |
return tswap64(val); |
360 | 361 |
} |
361 | 362 |
|
363 |
/* |
|
364 |
* CRQ handling |
|
365 |
*/ |
|
366 |
static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr, |
|
367 |
target_ulong opcode, target_ulong *args) |
|
368 |
{ |
|
369 |
target_ulong reg = args[0]; |
|
370 |
target_ulong queue_addr = args[1]; |
|
371 |
target_ulong queue_len = args[2]; |
|
372 |
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
|
373 |
|
|
374 |
if (!dev) { |
|
375 |
hcall_dprintf("h_reg_crq on non-existent unit 0x" |
|
376 |
TARGET_FMT_lx "\n", reg); |
|
377 |
return H_PARAMETER; |
|
378 |
} |
|
379 |
|
|
380 |
/* We can't grok a queue size bigger than 256M for now */ |
|
381 |
if (queue_len < 0x1000 || queue_len > 0x10000000) { |
|
382 |
hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n", |
|
383 |
(unsigned long long)queue_len); |
|
384 |
return H_PARAMETER; |
|
385 |
} |
|
386 |
|
|
387 |
/* Check queue alignment */ |
|
388 |
if (queue_addr & 0xfff) { |
|
389 |
hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n", |
|
390 |
(unsigned long long)queue_addr); |
|
391 |
return H_PARAMETER; |
|
392 |
} |
|
393 |
|
|
394 |
/* Check if device supports CRQs */ |
|
395 |
if (!dev->crq.SendFunc) { |
|
396 |
return H_NOT_FOUND; |
|
397 |
} |
|
398 |
|
|
399 |
|
|
400 |
/* Already a queue ? */ |
|
401 |
if (dev->crq.qsize) { |
|
402 |
return H_RESOURCE; |
|
403 |
} |
|
404 |
dev->crq.qladdr = queue_addr; |
|
405 |
dev->crq.qsize = queue_len; |
|
406 |
dev->crq.qnext = 0; |
|
407 |
|
|
408 |
dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" |
|
409 |
TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", |
|
410 |
reg, queue_addr, queue_len); |
|
411 |
return H_SUCCESS; |
|
412 |
} |
|
413 |
|
|
414 |
static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr, |
|
415 |
target_ulong opcode, target_ulong *args) |
|
416 |
{ |
|
417 |
target_ulong reg = args[0]; |
|
418 |
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
|
419 |
|
|
420 |
if (!dev) { |
|
421 |
hcall_dprintf("h_free_crq on non-existent unit 0x" |
|
422 |
TARGET_FMT_lx "\n", reg); |
|
423 |
return H_PARAMETER; |
|
424 |
} |
|
425 |
|
|
426 |
dev->crq.qladdr = 0; |
|
427 |
dev->crq.qsize = 0; |
|
428 |
dev->crq.qnext = 0; |
|
429 |
|
|
430 |
dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg); |
|
431 |
|
|
432 |
return H_SUCCESS; |
|
433 |
} |
|
434 |
|
|
435 |
static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr, |
|
436 |
target_ulong opcode, target_ulong *args) |
|
437 |
{ |
|
438 |
target_ulong reg = args[0]; |
|
439 |
target_ulong msg_hi = args[1]; |
|
440 |
target_ulong msg_lo = args[2]; |
|
441 |
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
|
442 |
uint64_t crq_mangle[2]; |
|
443 |
|
|
444 |
if (!dev) { |
|
445 |
hcall_dprintf("h_send_crq on non-existent unit 0x" |
|
446 |
TARGET_FMT_lx "\n", reg); |
|
447 |
return H_PARAMETER; |
|
448 |
} |
|
449 |
crq_mangle[0] = cpu_to_be64(msg_hi); |
|
450 |
crq_mangle[1] = cpu_to_be64(msg_lo); |
|
451 |
|
|
452 |
if (dev->crq.SendFunc) { |
|
453 |
return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); |
|
454 |
} |
|
455 |
|
|
456 |
return H_HARDWARE; |
|
457 |
} |
|
458 |
|
|
459 |
static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr, |
|
460 |
target_ulong opcode, target_ulong *args) |
|
461 |
{ |
|
462 |
target_ulong reg = args[0]; |
|
463 |
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); |
|
464 |
|
|
465 |
if (!dev) { |
|
466 |
hcall_dprintf("h_enable_crq on non-existent unit 0x" |
|
467 |
TARGET_FMT_lx "\n", reg); |
|
468 |
return H_PARAMETER; |
|
469 |
} |
|
470 |
|
|
471 |
return 0; |
|
472 |
} |
|
473 |
|
|
474 |
/* Returns negative error, 0 success, or positive: queue full */ |
|
475 |
int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) |
|
476 |
{ |
|
477 |
int rc; |
|
478 |
uint8_t byte; |
|
479 |
|
|
480 |
if (!dev->crq.qsize) { |
|
481 |
fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n"); |
|
482 |
return -1; |
|
483 |
} |
|
484 |
|
|
485 |
/* Maybe do a fast path for KVM just writing to the pages */ |
|
486 |
rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); |
|
487 |
if (rc) { |
|
488 |
return rc; |
|
489 |
} |
|
490 |
if (byte != 0) { |
|
491 |
return 1; |
|
492 |
} |
|
493 |
|
|
494 |
rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, |
|
495 |
&crq[8], 8); |
|
496 |
if (rc) { |
|
497 |
return rc; |
|
498 |
} |
|
499 |
|
|
500 |
kvmppc_eieio(); |
|
501 |
|
|
502 |
rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); |
|
503 |
if (rc) { |
|
504 |
return rc; |
|
505 |
} |
|
506 |
|
|
507 |
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; |
|
508 |
|
|
509 |
if (dev->signal_state & 1) { |
|
510 |
qemu_irq_pulse(dev->qirq); |
|
511 |
} |
|
512 |
|
|
513 |
return 0; |
|
514 |
} |
|
515 |
|
|
362 | 516 |
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) |
363 | 517 |
{ |
364 | 518 |
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; |
... | ... | |
431 | 585 |
/* hcall-tce */ |
432 | 586 |
spapr_register_hypercall(H_PUT_TCE, h_put_tce); |
433 | 587 |
|
588 |
/* hcall-crq */ |
|
589 |
spapr_register_hypercall(H_REG_CRQ, h_reg_crq); |
|
590 |
spapr_register_hypercall(H_FREE_CRQ, h_free_crq); |
|
591 |
spapr_register_hypercall(H_SEND_CRQ, h_send_crq); |
|
592 |
spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); |
|
593 |
|
|
434 | 594 |
for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { |
435 | 595 |
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; |
436 | 596 |
|
Also available in: Unified diff