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 22 void 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 37 void 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 50 int remote_iohub_map_irq(PCIDevice *pci_dev, int intx) 51 { 52 return pci_dev->devfn; 53 } 54 55 void 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 73 static 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 92 void 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