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
  13#include "hw/pci/pci.h"
  14#include "hw/pci/pci_ids.h"
  15#include "hw/pci/pci_bus.h"
  16#include "qemu/thread.h"
  17#include "hw/remote/machine.h"
  18#include "hw/remote/iohub.h"
  19#include "qemu/main-loop.h"
  20
  21void remote_iohub_init(RemoteIOHubState *iohub)
  22{
  23    int pirq;
  24
  25    memset(&iohub->irqfds, 0, sizeof(iohub->irqfds));
  26    memset(&iohub->resamplefds, 0, sizeof(iohub->resamplefds));
  27
  28    for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
  29        qemu_mutex_init(&iohub->irq_level_lock[pirq]);
  30        iohub->irq_level[pirq] = 0;
  31        event_notifier_init_fd(&iohub->irqfds[pirq], -1);
  32        event_notifier_init_fd(&iohub->resamplefds[pirq], -1);
  33    }
  34}
  35
  36void remote_iohub_finalize(RemoteIOHubState *iohub)
  37{
  38    int pirq;
  39
  40    for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
  41        qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
  42                            NULL, NULL, NULL);
  43        event_notifier_cleanup(&iohub->irqfds[pirq]);
  44        event_notifier_cleanup(&iohub->resamplefds[pirq]);
  45        qemu_mutex_destroy(&iohub->irq_level_lock[pirq]);
  46    }
  47}
  48
  49int remote_iohub_map_irq(PCIDevice *pci_dev, int intx)
  50{
  51    return pci_dev->devfn;
  52}
  53
  54void remote_iohub_set_irq(void *opaque, int pirq, int level)
  55{
  56    RemoteIOHubState *iohub = opaque;
  57
  58    assert(pirq >= 0);
  59    assert(pirq < PCI_DEVFN_MAX);
  60
  61    QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
  62
  63    if (level) {
  64        if (++iohub->irq_level[pirq] == 1) {
  65            event_notifier_set(&iohub->irqfds[pirq]);
  66        }
  67    } else if (iohub->irq_level[pirq] > 0) {
  68        iohub->irq_level[pirq]--;
  69    }
  70}
  71
  72static void intr_resample_handler(void *opaque)
  73{
  74    ResampleToken *token = opaque;
  75    RemoteIOHubState *iohub = token->iohub;
  76    int pirq, s;
  77
  78    pirq = token->pirq;
  79
  80    s = event_notifier_test_and_clear(&iohub->resamplefds[pirq]);
  81
  82    assert(s >= 0);
  83
  84    QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]);
  85
  86    if (iohub->irq_level[pirq]) {
  87        event_notifier_set(&iohub->irqfds[pirq]);
  88    }
  89}
  90
  91void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg)
  92{
  93    RemoteMachineState *machine = REMOTE_MACHINE(current_machine);
  94    RemoteIOHubState *iohub = &machine->iohub;
  95    int pirq, intx;
  96
  97    intx = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
  98
  99    pirq = remote_iohub_map_irq(pci_dev, intx);
 100
 101    if (event_notifier_get_fd(&iohub->irqfds[pirq]) != -1) {
 102        qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
 103                            NULL, NULL, NULL);
 104        event_notifier_cleanup(&iohub->irqfds[pirq]);
 105        event_notifier_cleanup(&iohub->resamplefds[pirq]);
 106        memset(&iohub->token[pirq], 0, sizeof(ResampleToken));
 107    }
 108
 109    event_notifier_init_fd(&iohub->irqfds[pirq], msg->fds[0]);
 110    event_notifier_init_fd(&iohub->resamplefds[pirq], msg->fds[1]);
 111
 112    iohub->token[pirq].iohub = iohub;
 113    iohub->token[pirq].pirq = pirq;
 114
 115    qemu_set_fd_handler(msg->fds[1], intr_resample_handler, NULL,
 116                        &iohub->token[pirq]);
 117}
 118