xref: /qemu/hw/intc/ioapic.c (revision f99b86b94987561580a94838766458e1c7b8685d)
1610626afSaliguori /*
2610626afSaliguori  *  ioapic.c IOAPIC emulation logic
3610626afSaliguori  *
4610626afSaliguori  *  Copyright (c) 2004-2005 Fabrice Bellard
5610626afSaliguori  *
6610626afSaliguori  *  Split the ioapic logic from apic.c
7610626afSaliguori  *  Xiantao Zhang <xiantao.zhang@intel.com>
8610626afSaliguori  *
9610626afSaliguori  * This library is free software; you can redistribute it and/or
10610626afSaliguori  * modify it under the terms of the GNU Lesser General Public
11610626afSaliguori  * License as published by the Free Software Foundation; either
12610626afSaliguori  * version 2 of the License, or (at your option) any later version.
13610626afSaliguori  *
14610626afSaliguori  * This library is distributed in the hope that it will be useful,
15610626afSaliguori  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16610626afSaliguori  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17610626afSaliguori  * Lesser General Public License for more details.
18610626afSaliguori  *
19610626afSaliguori  * You should have received a copy of the GNU Lesser General Public
208167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21610626afSaliguori  */
22610626afSaliguori 
23b6a0aa05SPeter Maydell #include "qemu/osdep.h"
246bde8fd6SPavel Butsykin #include "monitor/monitor.h"
2583c9f4caSPaolo Bonzini #include "hw/hw.h"
260d09e41aSPaolo Bonzini #include "hw/i386/pc.h"
27d613f8ccSPaolo Bonzini #include "hw/i386/apic.h"
280d09e41aSPaolo Bonzini #include "hw/i386/ioapic.h"
290d09e41aSPaolo Bonzini #include "hw/i386/ioapic_internal.h"
3015eafc2eSPaolo Bonzini #include "include/hw/pci/msi.h"
3115eafc2eSPaolo Bonzini #include "sysemu/kvm.h"
32cb135f59SPeter Xu #include "target-i386/cpu.h"
33cb135f59SPeter Xu #include "hw/i386/apic-msidef.h"
34e3d9c925SPeter Xu #include "hw/i386/x86-iommu.h"
35610626afSaliguori 
36610626afSaliguori //#define DEBUG_IOAPIC
37610626afSaliguori 
389af9b330SBlue Swirl #ifdef DEBUG_IOAPIC
399af9b330SBlue Swirl #define DPRINTF(fmt, ...)                                       \
409af9b330SBlue Swirl     do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
419af9b330SBlue Swirl #else
429af9b330SBlue Swirl #define DPRINTF(fmt, ...)
439af9b330SBlue Swirl #endif
449af9b330SBlue Swirl 
4515eafc2eSPaolo Bonzini #define APIC_DELIVERY_MODE_SHIFT 8
4615eafc2eSPaolo Bonzini #define APIC_POLARITY_SHIFT 14
4715eafc2eSPaolo Bonzini #define APIC_TRIG_MODE_SHIFT 15
4815eafc2eSPaolo Bonzini 
49244ac3afSJan Kiszka static IOAPICCommonState *ioapics[MAX_IOAPICS];
500280b571SJan Kiszka 
51db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */
52db0f8888Sxiaoqiang zhao extern int ioapic_no;
53db0f8888Sxiaoqiang zhao 
54c15fa0beSPeter Xu struct ioapic_entry_info {
55c15fa0beSPeter Xu     /* fields parsed from IOAPIC entries */
56c15fa0beSPeter Xu     uint8_t masked;
57c15fa0beSPeter Xu     uint8_t trig_mode;
58c15fa0beSPeter Xu     uint16_t dest_idx;
59c15fa0beSPeter Xu     uint8_t dest_mode;
60c15fa0beSPeter Xu     uint8_t delivery_mode;
61c15fa0beSPeter Xu     uint8_t vector;
62c15fa0beSPeter Xu 
63c15fa0beSPeter Xu     /* MSI message generated from above parsed fields */
64c15fa0beSPeter Xu     uint32_t addr;
65c15fa0beSPeter Xu     uint32_t data;
66c15fa0beSPeter Xu };
67c15fa0beSPeter Xu 
68c15fa0beSPeter Xu static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
69c15fa0beSPeter Xu {
70c15fa0beSPeter Xu     memset(info, 0, sizeof(*info));
71c15fa0beSPeter Xu     info->masked = (entry >> IOAPIC_LVT_MASKED_SHIFT) & 1;
72c15fa0beSPeter Xu     info->trig_mode = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
73c15fa0beSPeter Xu     /*
74c15fa0beSPeter Xu      * By default, this would be dest_id[8] + reserved[8]. When IR
75c15fa0beSPeter Xu      * is enabled, this would be interrupt_index[15] +
76c15fa0beSPeter Xu      * interrupt_format[1]. This field never means anything, but
77c15fa0beSPeter Xu      * only used to generate corresponding MSI.
78c15fa0beSPeter Xu      */
79c15fa0beSPeter Xu     info->dest_idx = (entry >> IOAPIC_LVT_DEST_IDX_SHIFT) & 0xffff;
80c15fa0beSPeter Xu     info->dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
81c15fa0beSPeter Xu     info->delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) \
82c15fa0beSPeter Xu         & IOAPIC_DM_MASK;
83c15fa0beSPeter Xu     if (info->delivery_mode == IOAPIC_DM_EXTINT) {
84c15fa0beSPeter Xu         info->vector = pic_read_irq(isa_pic);
85c15fa0beSPeter Xu     } else {
86c15fa0beSPeter Xu         info->vector = entry & IOAPIC_VECTOR_MASK;
87c15fa0beSPeter Xu     }
88c15fa0beSPeter Xu 
89c15fa0beSPeter Xu     info->addr = APIC_DEFAULT_ADDRESS | \
90c15fa0beSPeter Xu         (info->dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | \
91c15fa0beSPeter Xu         (info->dest_mode << MSI_ADDR_DEST_MODE_SHIFT);
92c15fa0beSPeter Xu     info->data = (info->vector << MSI_DATA_VECTOR_SHIFT) | \
93c15fa0beSPeter Xu         (info->trig_mode << MSI_DATA_TRIGGER_SHIFT) | \
94c15fa0beSPeter Xu         (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
95c15fa0beSPeter Xu }
96c15fa0beSPeter Xu 
97244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s)
98610626afSaliguori {
99cb135f59SPeter Xu     AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())->ioapic_as;
100c15fa0beSPeter Xu     struct ioapic_entry_info info;
101610626afSaliguori     uint8_t i;
102610626afSaliguori     uint32_t mask;
103610626afSaliguori     uint64_t entry;
104610626afSaliguori 
105610626afSaliguori     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
106610626afSaliguori         mask = 1 << i;
107610626afSaliguori         if (s->irr & mask) {
10815eafc2eSPaolo Bonzini             int coalesce = 0;
10915eafc2eSPaolo Bonzini 
110610626afSaliguori             entry = s->ioredtbl[i];
111c15fa0beSPeter Xu             ioapic_entry_parse(entry, &info);
112c15fa0beSPeter Xu             if (!info.masked) {
113c15fa0beSPeter Xu                 if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
114610626afSaliguori                     s->irr &= ~mask;
1150280b571SJan Kiszka                 } else {
11615eafc2eSPaolo Bonzini                     coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
1170280b571SJan Kiszka                     s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
1180280b571SJan Kiszka                 }
119c15fa0beSPeter Xu 
120*f99b86b9SPeter Xu                 if (coalesce) {
121*f99b86b9SPeter Xu                     /* We are level triggered interrupts, and the
122*f99b86b9SPeter Xu                      * guest should be still working on previous one,
123*f99b86b9SPeter Xu                      * so skip it. */
124*f99b86b9SPeter Xu                     continue;
125*f99b86b9SPeter Xu                 }
126*f99b86b9SPeter Xu 
12715eafc2eSPaolo Bonzini #ifdef CONFIG_KVM
12815eafc2eSPaolo Bonzini                 if (kvm_irqchip_is_split()) {
129c15fa0beSPeter Xu                     if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
13015eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 1);
13115eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 0);
13215eafc2eSPaolo Bonzini                     } else {
13315eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 1);
13415eafc2eSPaolo Bonzini                     }
13515eafc2eSPaolo Bonzini                     continue;
13615eafc2eSPaolo Bonzini                 }
13715eafc2eSPaolo Bonzini #endif
138*f99b86b9SPeter Xu 
139cb135f59SPeter Xu                 /* No matter whether IR is enabled, we translate
140cb135f59SPeter Xu                  * the IOAPIC message into a MSI one, and its
141cb135f59SPeter Xu                  * address space will decide whether we need a
142cb135f59SPeter Xu                  * translation. */
143c15fa0beSPeter Xu                 stl_le_phys(ioapic_as, info.addr, info.data);
144610626afSaliguori             }
145610626afSaliguori         }
146610626afSaliguori     }
147610626afSaliguori }
148610626afSaliguori 
1497d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level)
150610626afSaliguori {
151244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
152610626afSaliguori 
153610626afSaliguori     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
154610626afSaliguori      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
155610626afSaliguori      * the cleanest way of doing it but it should work. */
156610626afSaliguori 
1579af9b330SBlue Swirl     DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
1581f5e71a8SJan Kiszka     if (vector == 0) {
159610626afSaliguori         vector = 2;
1601f5e71a8SJan Kiszka     }
161610626afSaliguori     if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
162610626afSaliguori         uint32_t mask = 1 << vector;
163610626afSaliguori         uint64_t entry = s->ioredtbl[vector];
164610626afSaliguori 
1651f5e71a8SJan Kiszka         if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
1661f5e71a8SJan Kiszka             IOAPIC_TRIGGER_LEVEL) {
167610626afSaliguori             /* level triggered */
168610626afSaliguori             if (level) {
169610626afSaliguori                 s->irr |= mask;
170c5955a56SPaolo Bonzini                 if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
171610626afSaliguori                     ioapic_service(s);
172c5955a56SPaolo Bonzini                 }
173610626afSaliguori             } else {
174610626afSaliguori                 s->irr &= ~mask;
175610626afSaliguori             }
176610626afSaliguori         } else {
17747f7be39SJan Kiszka             /* According to the 82093AA manual, we must ignore edge requests
17847f7be39SJan Kiszka              * if the input pin is masked. */
17947f7be39SJan Kiszka             if (level && !(entry & IOAPIC_LVT_MASKED)) {
180610626afSaliguori                 s->irr |= mask;
181610626afSaliguori                 ioapic_service(s);
182610626afSaliguori             }
183610626afSaliguori         }
184610626afSaliguori     }
185610626afSaliguori }
186610626afSaliguori 
18715eafc2eSPaolo Bonzini static void ioapic_update_kvm_routes(IOAPICCommonState *s)
18815eafc2eSPaolo Bonzini {
18915eafc2eSPaolo Bonzini #ifdef CONFIG_KVM
19015eafc2eSPaolo Bonzini     int i;
19115eafc2eSPaolo Bonzini 
19215eafc2eSPaolo Bonzini     if (kvm_irqchip_is_split()) {
19315eafc2eSPaolo Bonzini         for (i = 0; i < IOAPIC_NUM_PINS; i++) {
19415eafc2eSPaolo Bonzini             MSIMessage msg;
195c15fa0beSPeter Xu             struct ioapic_entry_info info;
196c15fa0beSPeter Xu             ioapic_entry_parse(s->ioredtbl[i], &info);
197c15fa0beSPeter Xu             msg.address = info.addr;
198c15fa0beSPeter Xu             msg.data = info.data;
19915eafc2eSPaolo Bonzini             kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
20015eafc2eSPaolo Bonzini         }
20115eafc2eSPaolo Bonzini         kvm_irqchip_commit_routes(kvm_state);
20215eafc2eSPaolo Bonzini     }
20315eafc2eSPaolo Bonzini #endif
20415eafc2eSPaolo Bonzini }
20515eafc2eSPaolo Bonzini 
206e3d9c925SPeter Xu #ifdef CONFIG_KVM
207e3d9c925SPeter Xu static void ioapic_iec_notifier(void *private, bool global,
208e3d9c925SPeter Xu                                 uint32_t index, uint32_t mask)
209e3d9c925SPeter Xu {
210e3d9c925SPeter Xu     IOAPICCommonState *s = (IOAPICCommonState *)private;
211e3d9c925SPeter Xu     /* For simplicity, we just update all the routes */
212e3d9c925SPeter Xu     ioapic_update_kvm_routes(s);
213e3d9c925SPeter Xu }
214e3d9c925SPeter Xu #endif
215e3d9c925SPeter Xu 
2160280b571SJan Kiszka void ioapic_eoi_broadcast(int vector)
2170280b571SJan Kiszka {
218244ac3afSJan Kiszka     IOAPICCommonState *s;
2190280b571SJan Kiszka     uint64_t entry;
2200280b571SJan Kiszka     int i, n;
2210280b571SJan Kiszka 
2220280b571SJan Kiszka     for (i = 0; i < MAX_IOAPICS; i++) {
2230280b571SJan Kiszka         s = ioapics[i];
2240280b571SJan Kiszka         if (!s) {
2250280b571SJan Kiszka             continue;
2260280b571SJan Kiszka         }
2270280b571SJan Kiszka         for (n = 0; n < IOAPIC_NUM_PINS; n++) {
2280280b571SJan Kiszka             entry = s->ioredtbl[n];
2291f5e71a8SJan Kiszka             if ((entry & IOAPIC_LVT_REMOTE_IRR)
2301f5e71a8SJan Kiszka                 && (entry & IOAPIC_VECTOR_MASK) == vector) {
2310280b571SJan Kiszka                 s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
2320280b571SJan Kiszka                 if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
2330280b571SJan Kiszka                     ioapic_service(s);
2340280b571SJan Kiszka                 }
2350280b571SJan Kiszka             }
2360280b571SJan Kiszka         }
2370280b571SJan Kiszka     }
2380280b571SJan Kiszka }
2390280b571SJan Kiszka 
2406bde8fd6SPavel Butsykin void ioapic_dump_state(Monitor *mon, const QDict *qdict)
2416bde8fd6SPavel Butsykin {
2426bde8fd6SPavel Butsykin     int i;
2436bde8fd6SPavel Butsykin 
2446bde8fd6SPavel Butsykin     for (i = 0; i < MAX_IOAPICS; i++) {
2456bde8fd6SPavel Butsykin         if (ioapics[i] != 0) {
2466bde8fd6SPavel Butsykin             ioapic_print_redtbl(mon, ioapics[i]);
2476bde8fd6SPavel Butsykin         }
2486bde8fd6SPavel Butsykin     }
2496bde8fd6SPavel Butsykin }
2506bde8fd6SPavel Butsykin 
2514d5bf5f6SJan Kiszka static uint64_t
252a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
253610626afSaliguori {
254244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
255610626afSaliguori     int index;
256610626afSaliguori     uint32_t val = 0;
257610626afSaliguori 
2581f5e71a8SJan Kiszka     switch (addr & 0xff) {
2591f5e71a8SJan Kiszka     case IOAPIC_IOREGSEL:
260610626afSaliguori         val = s->ioregsel;
2611f5e71a8SJan Kiszka         break;
2621f5e71a8SJan Kiszka     case IOAPIC_IOWIN:
2631a440963SJan Kiszka         if (size != 4) {
2641a440963SJan Kiszka             break;
2651a440963SJan Kiszka         }
266610626afSaliguori         switch (s->ioregsel) {
2671f5e71a8SJan Kiszka         case IOAPIC_REG_ID:
2682f5a3b12SPaolo Bonzini         case IOAPIC_REG_ARB:
2691f5e71a8SJan Kiszka             val = s->id << IOAPIC_ID_SHIFT;
270610626afSaliguori             break;
2711f5e71a8SJan Kiszka         case IOAPIC_REG_VER:
2721f5e71a8SJan Kiszka             val = IOAPIC_VERSION |
2731f5e71a8SJan Kiszka                 ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
274610626afSaliguori             break;
275610626afSaliguori         default:
2761f5e71a8SJan Kiszka             index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
277610626afSaliguori             if (index >= 0 && index < IOAPIC_NUM_PINS) {
2781f5e71a8SJan Kiszka                 if (s->ioregsel & 1) {
279610626afSaliguori                     val = s->ioredtbl[index] >> 32;
2801f5e71a8SJan Kiszka                 } else {
281610626afSaliguori                     val = s->ioredtbl[index] & 0xffffffff;
282610626afSaliguori                 }
283610626afSaliguori             }
2841f5e71a8SJan Kiszka         }
2859af9b330SBlue Swirl         DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
2861f5e71a8SJan Kiszka         break;
287610626afSaliguori     }
288610626afSaliguori     return val;
289610626afSaliguori }
290610626afSaliguori 
291ed1263c3SPeter Xu /*
292ed1263c3SPeter Xu  * This is to satisfy the hack in Linux kernel. One hack of it is to
293ed1263c3SPeter Xu  * simulate clearing the Remote IRR bit of IOAPIC entry using the
294ed1263c3SPeter Xu  * following:
295ed1263c3SPeter Xu  *
296ed1263c3SPeter Xu  * "For IO-APIC's with EOI register, we use that to do an explicit EOI.
297ed1263c3SPeter Xu  * Otherwise, we simulate the EOI message manually by changing the trigger
298ed1263c3SPeter Xu  * mode to edge and then back to level, with RTE being masked during
299ed1263c3SPeter Xu  * this."
300ed1263c3SPeter Xu  *
301ed1263c3SPeter Xu  * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701)
302ed1263c3SPeter Xu  *
303ed1263c3SPeter Xu  * This is based on the assumption that, Remote IRR bit will be
304ed1263c3SPeter Xu  * cleared by IOAPIC hardware when configured as edge-triggered
305ed1263c3SPeter Xu  * interrupts.
306ed1263c3SPeter Xu  *
307ed1263c3SPeter Xu  * Without this, level-triggered interrupts in IR mode might fail to
308ed1263c3SPeter Xu  * work correctly.
309ed1263c3SPeter Xu  */
310ed1263c3SPeter Xu static inline void
311ed1263c3SPeter Xu ioapic_fix_edge_remote_irr(uint64_t *entry)
312ed1263c3SPeter Xu {
313ed1263c3SPeter Xu     if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) {
314ed1263c3SPeter Xu         /* Edge-triggered interrupts, make sure remote IRR is zero */
315ed1263c3SPeter Xu         *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR);
316ed1263c3SPeter Xu     }
317ed1263c3SPeter Xu }
318ed1263c3SPeter Xu 
3191f5e71a8SJan Kiszka static void
320a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
3214d5bf5f6SJan Kiszka                  unsigned int size)
322610626afSaliguori {
323244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
324610626afSaliguori     int index;
325610626afSaliguori 
3261f5e71a8SJan Kiszka     switch (addr & 0xff) {
3271f5e71a8SJan Kiszka     case IOAPIC_IOREGSEL:
328610626afSaliguori         s->ioregsel = val;
3291f5e71a8SJan Kiszka         break;
3301f5e71a8SJan Kiszka     case IOAPIC_IOWIN:
3311a440963SJan Kiszka         if (size != 4) {
3321a440963SJan Kiszka             break;
3331a440963SJan Kiszka         }
3340c1f781bSJason Wang         DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
335610626afSaliguori         switch (s->ioregsel) {
3361f5e71a8SJan Kiszka         case IOAPIC_REG_ID:
3371f5e71a8SJan Kiszka             s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
3381f5e71a8SJan Kiszka             break;
3391f5e71a8SJan Kiszka         case IOAPIC_REG_VER:
3401f5e71a8SJan Kiszka         case IOAPIC_REG_ARB:
3411f5e71a8SJan Kiszka             break;
342610626afSaliguori         default:
3431f5e71a8SJan Kiszka             index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
344610626afSaliguori             if (index >= 0 && index < IOAPIC_NUM_PINS) {
345479c2a1cSPeter Xu                 uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS;
346610626afSaliguori                 if (s->ioregsel & 1) {
347610626afSaliguori                     s->ioredtbl[index] &= 0xffffffff;
348610626afSaliguori                     s->ioredtbl[index] |= (uint64_t)val << 32;
349610626afSaliguori                 } else {
350610626afSaliguori                     s->ioredtbl[index] &= ~0xffffffffULL;
351610626afSaliguori                     s->ioredtbl[index] |= val;
352610626afSaliguori                 }
353479c2a1cSPeter Xu                 /* restore RO bits */
354479c2a1cSPeter Xu                 s->ioredtbl[index] &= IOAPIC_RW_BITS;
355479c2a1cSPeter Xu                 s->ioredtbl[index] |= ro_bits;
356ed1263c3SPeter Xu                 ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
357610626afSaliguori                 ioapic_service(s);
358610626afSaliguori             }
359610626afSaliguori         }
3601f5e71a8SJan Kiszka         break;
361610626afSaliguori     }
36215eafc2eSPaolo Bonzini 
36315eafc2eSPaolo Bonzini     ioapic_update_kvm_routes(s);
364610626afSaliguori }
365610626afSaliguori 
3664d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = {
3674d5bf5f6SJan Kiszka     .read = ioapic_mem_read,
3684d5bf5f6SJan Kiszka     .write = ioapic_mem_write,
3694d5bf5f6SJan Kiszka     .endianness = DEVICE_NATIVE_ENDIAN,
370610626afSaliguori };
371610626afSaliguori 
372e3d9c925SPeter Xu static void ioapic_machine_done_notify(Notifier *notifier, void *data)
373e3d9c925SPeter Xu {
374e3d9c925SPeter Xu #ifdef CONFIG_KVM
375e3d9c925SPeter Xu     IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
376e3d9c925SPeter Xu                                         machine_done);
377e3d9c925SPeter Xu 
378e3d9c925SPeter Xu     if (kvm_irqchip_is_split()) {
379e3d9c925SPeter Xu         X86IOMMUState *iommu = x86_iommu_get_default();
380e3d9c925SPeter Xu         if (iommu) {
381e3d9c925SPeter Xu             /* Register this IOAPIC with IOMMU IEC notifier, so that
382e3d9c925SPeter Xu              * when there are IR invalidates, we can be notified to
383e3d9c925SPeter Xu              * update kernel IR cache. */
384e3d9c925SPeter Xu             x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s);
385e3d9c925SPeter Xu         }
386e3d9c925SPeter Xu     }
387e3d9c925SPeter Xu #endif
388e3d9c925SPeter Xu }
389e3d9c925SPeter Xu 
390db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp)
391610626afSaliguori {
392db0f8888Sxiaoqiang zhao     IOAPICCommonState *s = IOAPIC_COMMON(dev);
393f9771858Sxiaoqiang zhao 
3941437c94bSPaolo Bonzini     memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
3951437c94bSPaolo Bonzini                           "ioapic", 0x1000);
396610626afSaliguori 
397f9771858Sxiaoqiang zhao     qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
398610626afSaliguori 
399db0f8888Sxiaoqiang zhao     ioapics[ioapic_no] = s;
400e3d9c925SPeter Xu     s->machine_done.notify = ioapic_machine_done_notify;
401e3d9c925SPeter Xu     qemu_add_machine_init_done_notifier(&s->machine_done);
402610626afSaliguori }
40396051119SBlue Swirl 
404999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data)
405999e12bbSAnthony Liguori {
406999e12bbSAnthony Liguori     IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
40739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
408999e12bbSAnthony Liguori 
409db0f8888Sxiaoqiang zhao     k->realize = ioapic_realize;
41039bffca2SAnthony Liguori     dc->reset = ioapic_reset_common;
411999e12bbSAnthony Liguori }
412999e12bbSAnthony Liguori 
4138c43a6f0SAndreas Färber static const TypeInfo ioapic_info = {
414999e12bbSAnthony Liguori     .name          = "ioapic",
41539bffca2SAnthony Liguori     .parent        = TYPE_IOAPIC_COMMON,
41639bffca2SAnthony Liguori     .instance_size = sizeof(IOAPICCommonState),
417999e12bbSAnthony Liguori     .class_init    = ioapic_class_init,
41896051119SBlue Swirl };
41996051119SBlue Swirl 
42083f7d43aSAndreas Färber static void ioapic_register_types(void)
42196051119SBlue Swirl {
42239bffca2SAnthony Liguori     type_register_static(&ioapic_info);
42396051119SBlue Swirl }
42496051119SBlue Swirl 
42583f7d43aSAndreas Färber type_init(ioapic_register_types)
426