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 23 void 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 38 void 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 51 int remote_iohub_map_irq(PCIDevice *pci_dev, int intx) 52 { 53 return pci_dev->devfn; 54 } 55 56 void 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 74 static 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 93 void 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