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