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 21 void 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 36 int remote_iohub_map_irq(PCIDevice *pci_dev, int intx) 37 { 38 return pci_dev->devfn; 39 } 40 41 void remote_iohub_set_irq(void *opaque, int pirq, int level) 42 { 43 RemoteIOHubState *iohub = opaque; 44 45 assert(pirq >= 0); 46 assert(pirq < PCI_DEVFN_MAX); 47 48 QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]); 49 50 if (level) { 51 if (++iohub->irq_level[pirq] == 1) { 52 event_notifier_set(&iohub->irqfds[pirq]); 53 } 54 } else if (iohub->irq_level[pirq] > 0) { 55 iohub->irq_level[pirq]--; 56 } 57 } 58 59 static void intr_resample_handler(void *opaque) 60 { 61 ResampleToken *token = opaque; 62 RemoteIOHubState *iohub = token->iohub; 63 int pirq, s; 64 65 pirq = token->pirq; 66 67 s = event_notifier_test_and_clear(&iohub->resamplefds[pirq]); 68 69 assert(s >= 0); 70 71 QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]); 72 73 if (iohub->irq_level[pirq]) { 74 event_notifier_set(&iohub->irqfds[pirq]); 75 } 76 } 77 78 void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg) 79 { 80 RemoteMachineState *machine = REMOTE_MACHINE(current_machine); 81 RemoteIOHubState *iohub = &machine->iohub; 82 int pirq, intx; 83 84 intx = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; 85 86 pirq = remote_iohub_map_irq(pci_dev, intx); 87 88 if (event_notifier_get_fd(&iohub->irqfds[pirq]) != -1) { 89 qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]), 90 NULL, NULL, NULL); 91 event_notifier_cleanup(&iohub->irqfds[pirq]); 92 event_notifier_cleanup(&iohub->resamplefds[pirq]); 93 memset(&iohub->token[pirq], 0, sizeof(ResampleToken)); 94 } 95 96 event_notifier_init_fd(&iohub->irqfds[pirq], msg->fds[0]); 97 event_notifier_init_fd(&iohub->resamplefds[pirq], msg->fds[1]); 98 99 iohub->token[pirq].iohub = iohub; 100 iohub->token[pirq].pirq = pirq; 101 102 qemu_set_fd_handler(msg->fds[1], intr_resample_handler, NULL, 103 &iohub->token[pirq]); 104 } 105