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 void 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 49 int remote_iohub_map_irq(PCIDevice *pci_dev, int intx) 50 { 51 return pci_dev->devfn; 52 } 53 54 void 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 72 static 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 91 void 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