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