xref: /openbmc/qemu/hw/remote/iohub.c (revision 40f23e4e)
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