qemu/hw/remote/iohub.c
<<
>>
Prefs
   1/*
   2 * Remote IO Hub
   3 *
   4 * Copyright © 2018, 2021 Oracle and/or its affiliates.
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 *
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "qemu-common.h"
  13
  14#include "hw/pci/pci.h"
  15#include "hw/pci/pci_ids.h"
  16#include "hw/pci/pci_bus.h"
  17#include "qemu/thread.h"
  18#include "hw/remote/machine.h"
  19#include "hw/remote/iohub.h"
  20#include "qemu/main-loop.h"
  21
  22void remote_iohub_init(RemoteIOHubState *iohub)
  23{
  24    int pirq;
  25
  26    memset(&iohub->irqfds, 0, sizeof(iohub->irqfds));
  27    memset(&iohub->resamplefds, 0, sizeof(iohub->resamplefds));
  28
  29    for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
  30        qemu_mutex_init(&iohub->irq_level_lock[pirq]);
  31        iohub->irq_level[pirq] = 0;
  32        event_notifier_init_fd(&iohub->irqfds[pirq], -1);
  33        event_notifier_init_fd(&iohub->resamplefds[pirq], -1);
  34    }
  35}
  36
  37void remote_iohub_finalize(RemoteIOHubState *iohub)
  38{
  39    int pirq;
  40
  41    for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
  42        qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
  43                            NULL, NULL, NULL);
  44        event_notifier_cleanup(&iohub->irqfds[pirq]);
  45        event_notifier_cleanup(&iohub->resamplefds[pirq]);
  46        qemu_mutex_destroy(&iohub->irq_level_lock[pirq]);
  47    }
  48}
  49
  50int remote_iohub_map_irq(PCIDevice *pci_dev, int intx)
  51{
  52    return pci_dev->devfn;
  53}
  54
  55void remote_iohub_set_irq(void *opaque, int pirq, int level)
  56{
  57    RemoteIOHubState *iohub = opaque;
  58
  59    assert(pirq >= 0);
  60    assert(pirq < PCI_DEVFN_MAX);
  61
  62    QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
  63
  64    if (level) {
  65        if (++iohub->irq_level[pirq] == 1) {
  66            event_notifier_set(&iohub->irqfds[pirq]);
  67        }
  68    } else if (iohub->irq_level[pirq] > 0) {
  69        iohub->irq_level[pirq]--;
  70    }
  71}
  72
  73static void intr_resample_handler(void *opaque)
  74{
  75    ResampleToken *token = opaque;
  76    RemoteIOHubState *iohub = token->iohub;
  77    int pirq, s;
  78
  79    pirq = token->pirq;
  80
  81    s = event_notifier_test_and_clear(&iohub->resamplefds[pirq]);
  82
  83    assert(s >= 0);
  84
  85    QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
  86
  87    if (iohub->irq_level[pirq]) {
  88        event_notifier_set(&iohub->irqfds[pirq]);
  89    }
  90}
  91
  92void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg)
  93{
  94    RemoteMachineState *machine = REMOTE_MACHINE(current_machine);
  95    RemoteIOHubState *iohub = &machine->iohub;
  96    int pirq, intx;
  97
  98    intx = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
  99
 100    pirq = remote_iohub_map_irq(pci_dev, intx);
 101
 102    if (event_notifier_get_fd(&iohub->irqfds[pirq]) != -1) {
 103        qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
 104                            NULL, NULL, NULL);
 105        event_notifier_cleanup(&iohub->irqfds[pirq]);
 106        event_notifier_cleanup(&iohub->resamplefds[pirq]);
 107        memset(&iohub->token[pirq], 0, sizeof(ResampleToken));
 108    }
 109
 110    event_notifier_init_fd(&iohub->irqfds[pirq], msg->fds[0]);
 111    event_notifier_init_fd(&iohub->resamplefds[pirq], msg->fds[1]);
 112
 113    iohub->token[pirq].iohub = iohub;
 114    iohub->token[pirq].pirq = pirq;
 115
 116    qemu_set_fd_handler(msg->fds[1], intr_resample_handler, NULL,
 117                        &iohub->token[pirq]);
 118}
 119