xref: /openbmc/qemu/hw/acpi/pcihp.c (revision db4728e6fec0364b866d3106125974eedc00e091)
1*db4728e6SMichael S. Tsirkin /*
2*db4728e6SMichael S. Tsirkin  * QEMU<->ACPI BIOS PCI hotplug interface
3*db4728e6SMichael S. Tsirkin  *
4*db4728e6SMichael S. Tsirkin  * QEMU supports PCI hotplug via ACPI. This module
5*db4728e6SMichael S. Tsirkin  * implements the interface between QEMU and the ACPI BIOS.
6*db4728e6SMichael S. Tsirkin  * Interface specification - see docs/specs/acpi_pci_hotplug.txt
7*db4728e6SMichael S. Tsirkin  *
8*db4728e6SMichael S. Tsirkin  * Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
9*db4728e6SMichael S. Tsirkin  * Copyright (c) 2006 Fabrice Bellard
10*db4728e6SMichael S. Tsirkin  *
11*db4728e6SMichael S. Tsirkin  * This library is free software; you can redistribute it and/or
12*db4728e6SMichael S. Tsirkin  * modify it under the terms of the GNU Lesser General Public
13*db4728e6SMichael S. Tsirkin  * License version 2 as published by the Free Software Foundation.
14*db4728e6SMichael S. Tsirkin  *
15*db4728e6SMichael S. Tsirkin  * This library is distributed in the hope that it will be useful,
16*db4728e6SMichael S. Tsirkin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*db4728e6SMichael S. Tsirkin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18*db4728e6SMichael S. Tsirkin  * Lesser General Public License for more details.
19*db4728e6SMichael S. Tsirkin  *
20*db4728e6SMichael S. Tsirkin  * You should have received a copy of the GNU Lesser General Public
21*db4728e6SMichael S. Tsirkin  * License along with this library; if not, see <http://www.gnu.org/licenses/>
22*db4728e6SMichael S. Tsirkin  *
23*db4728e6SMichael S. Tsirkin  * Contributions after 2012-01-13 are licensed under the terms of the
24*db4728e6SMichael S. Tsirkin  * GNU GPL, version 2 or (at your option) any later version.
25*db4728e6SMichael S. Tsirkin  */
26*db4728e6SMichael S. Tsirkin 
27*db4728e6SMichael S. Tsirkin #include "hw/acpi/pcihp.h"
28*db4728e6SMichael S. Tsirkin 
29*db4728e6SMichael S. Tsirkin #include "hw/hw.h"
30*db4728e6SMichael S. Tsirkin #include "hw/i386/pc.h"
31*db4728e6SMichael S. Tsirkin #include "hw/pci/pci.h"
32*db4728e6SMichael S. Tsirkin #include "hw/acpi/acpi.h"
33*db4728e6SMichael S. Tsirkin #include "sysemu/sysemu.h"
34*db4728e6SMichael S. Tsirkin #include "qemu/range.h"
35*db4728e6SMichael S. Tsirkin #include "exec/ioport.h"
36*db4728e6SMichael S. Tsirkin #include "exec/address-spaces.h"
37*db4728e6SMichael S. Tsirkin #include "hw/pci/pci_bus.h"
38*db4728e6SMichael S. Tsirkin #include "qom/qom-qobject.h"
39*db4728e6SMichael S. Tsirkin #include "qapi/qmp/qint.h"
40*db4728e6SMichael S. Tsirkin 
41*db4728e6SMichael S. Tsirkin //#define DEBUG
42*db4728e6SMichael S. Tsirkin 
43*db4728e6SMichael S. Tsirkin #ifdef DEBUG
44*db4728e6SMichael S. Tsirkin # define ACPI_PCIHP_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
45*db4728e6SMichael S. Tsirkin #else
46*db4728e6SMichael S. Tsirkin # define ACPI_PCIHP_DPRINTF(format, ...)     do { } while (0)
47*db4728e6SMichael S. Tsirkin #endif
48*db4728e6SMichael S. Tsirkin 
49*db4728e6SMichael S. Tsirkin #define PCI_HOTPLUG_ADDR 0xae00
50*db4728e6SMichael S. Tsirkin #define PCI_HOTPLUG_SIZE 0x0014
51*db4728e6SMichael S. Tsirkin #define PCI_UP_BASE 0xae00
52*db4728e6SMichael S. Tsirkin #define PCI_DOWN_BASE 0xae04
53*db4728e6SMichael S. Tsirkin #define PCI_EJ_BASE 0xae08
54*db4728e6SMichael S. Tsirkin #define PCI_RMV_BASE 0xae0c
55*db4728e6SMichael S. Tsirkin #define PCI_SEL_BASE 0xae10
56*db4728e6SMichael S. Tsirkin 
57*db4728e6SMichael S. Tsirkin typedef struct AcpiPciHpFind {
58*db4728e6SMichael S. Tsirkin     int bsel;
59*db4728e6SMichael S. Tsirkin     PCIBus *bus;
60*db4728e6SMichael S. Tsirkin } AcpiPciHpFind;
61*db4728e6SMichael S. Tsirkin 
62*db4728e6SMichael S. Tsirkin static int acpi_pcihp_get_bsel(PCIBus *bus)
63*db4728e6SMichael S. Tsirkin {
64*db4728e6SMichael S. Tsirkin     QObject *o = object_property_get_qobject(OBJECT(bus),
65*db4728e6SMichael S. Tsirkin                                              ACPI_PCIHP_PROP_BSEL, NULL);
66*db4728e6SMichael S. Tsirkin     int64_t bsel = -1;
67*db4728e6SMichael S. Tsirkin     if (o) {
68*db4728e6SMichael S. Tsirkin         bsel = qint_get_int(qobject_to_qint(o));
69*db4728e6SMichael S. Tsirkin     }
70*db4728e6SMichael S. Tsirkin     if (bsel < 0) {
71*db4728e6SMichael S. Tsirkin         return -1;
72*db4728e6SMichael S. Tsirkin     }
73*db4728e6SMichael S. Tsirkin     return bsel;
74*db4728e6SMichael S. Tsirkin }
75*db4728e6SMichael S. Tsirkin 
76*db4728e6SMichael S. Tsirkin static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
77*db4728e6SMichael S. Tsirkin {
78*db4728e6SMichael S. Tsirkin     AcpiPciHpFind *find = opaque;
79*db4728e6SMichael S. Tsirkin     if (find->bsel == acpi_pcihp_get_bsel(bus)) {
80*db4728e6SMichael S. Tsirkin         find->bus = bus;
81*db4728e6SMichael S. Tsirkin     }
82*db4728e6SMichael S. Tsirkin }
83*db4728e6SMichael S. Tsirkin 
84*db4728e6SMichael S. Tsirkin static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel)
85*db4728e6SMichael S. Tsirkin {
86*db4728e6SMichael S. Tsirkin     AcpiPciHpFind find = { .bsel = bsel, .bus = NULL };
87*db4728e6SMichael S. Tsirkin 
88*db4728e6SMichael S. Tsirkin     if (bsel < 0) {
89*db4728e6SMichael S. Tsirkin         return NULL;
90*db4728e6SMichael S. Tsirkin     }
91*db4728e6SMichael S. Tsirkin 
92*db4728e6SMichael S. Tsirkin     pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find);
93*db4728e6SMichael S. Tsirkin 
94*db4728e6SMichael S. Tsirkin     /* Make bsel 0 eject root bus if bsel property is not set,
95*db4728e6SMichael S. Tsirkin      * for compatibility with non acpi setups.
96*db4728e6SMichael S. Tsirkin      * TODO: really needed?
97*db4728e6SMichael S. Tsirkin      */
98*db4728e6SMichael S. Tsirkin     if (!bsel && !find.bus) {
99*db4728e6SMichael S. Tsirkin         find.bus = s->root;
100*db4728e6SMichael S. Tsirkin     }
101*db4728e6SMichael S. Tsirkin     return find.bus;
102*db4728e6SMichael S. Tsirkin }
103*db4728e6SMichael S. Tsirkin 
104*db4728e6SMichael S. Tsirkin static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
105*db4728e6SMichael S. Tsirkin {
106*db4728e6SMichael S. Tsirkin     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
107*db4728e6SMichael S. Tsirkin     /*
108*db4728e6SMichael S. Tsirkin      * ACPI doesn't allow hotplug of bridge devices.  Don't allow
109*db4728e6SMichael S. Tsirkin      * hot-unplug of bridge devices unless they were added by hotplug
110*db4728e6SMichael S. Tsirkin      * (and so, not described by acpi).
111*db4728e6SMichael S. Tsirkin      */
112*db4728e6SMichael S. Tsirkin     return (pc->is_bridge && !dev->qdev.hotplugged) || pc->no_hotplug;
113*db4728e6SMichael S. Tsirkin }
114*db4728e6SMichael S. Tsirkin 
115*db4728e6SMichael S. Tsirkin static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
116*db4728e6SMichael S. Tsirkin {
117*db4728e6SMichael S. Tsirkin     BusChild *kid, *next;
118*db4728e6SMichael S. Tsirkin     int slot = ffs(slots) - 1;
119*db4728e6SMichael S. Tsirkin     bool slot_free = true;
120*db4728e6SMichael S. Tsirkin     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
121*db4728e6SMichael S. Tsirkin 
122*db4728e6SMichael S. Tsirkin     if (!bus) {
123*db4728e6SMichael S. Tsirkin         return;
124*db4728e6SMichael S. Tsirkin     }
125*db4728e6SMichael S. Tsirkin 
126*db4728e6SMichael S. Tsirkin     /* Mark request as complete */
127*db4728e6SMichael S. Tsirkin     s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot);
128*db4728e6SMichael S. Tsirkin 
129*db4728e6SMichael S. Tsirkin     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
130*db4728e6SMichael S. Tsirkin         DeviceState *qdev = kid->child;
131*db4728e6SMichael S. Tsirkin         PCIDevice *dev = PCI_DEVICE(qdev);
132*db4728e6SMichael S. Tsirkin         if (PCI_SLOT(dev->devfn) == slot) {
133*db4728e6SMichael S. Tsirkin             if (acpi_pcihp_pc_no_hotplug(s, dev)) {
134*db4728e6SMichael S. Tsirkin                 slot_free = false;
135*db4728e6SMichael S. Tsirkin             } else {
136*db4728e6SMichael S. Tsirkin                 object_unparent(OBJECT(qdev));
137*db4728e6SMichael S. Tsirkin             }
138*db4728e6SMichael S. Tsirkin         }
139*db4728e6SMichael S. Tsirkin     }
140*db4728e6SMichael S. Tsirkin     if (slot_free) {
141*db4728e6SMichael S. Tsirkin         s->acpi_pcihp_pci_status[bsel].device_present &= ~(1U << slot);
142*db4728e6SMichael S. Tsirkin     }
143*db4728e6SMichael S. Tsirkin }
144*db4728e6SMichael S. Tsirkin 
145*db4728e6SMichael S. Tsirkin static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
146*db4728e6SMichael S. Tsirkin {
147*db4728e6SMichael S. Tsirkin     BusChild *kid, *next;
148*db4728e6SMichael S. Tsirkin     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
149*db4728e6SMichael S. Tsirkin 
150*db4728e6SMichael S. Tsirkin     /* Execute any pending removes during reset */
151*db4728e6SMichael S. Tsirkin     while (s->acpi_pcihp_pci_status[bsel].down) {
152*db4728e6SMichael S. Tsirkin         acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down);
153*db4728e6SMichael S. Tsirkin     }
154*db4728e6SMichael S. Tsirkin 
155*db4728e6SMichael S. Tsirkin     s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0;
156*db4728e6SMichael S. Tsirkin     s->acpi_pcihp_pci_status[bsel].device_present = 0;
157*db4728e6SMichael S. Tsirkin 
158*db4728e6SMichael S. Tsirkin     if (!bus) {
159*db4728e6SMichael S. Tsirkin         return;
160*db4728e6SMichael S. Tsirkin     }
161*db4728e6SMichael S. Tsirkin     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
162*db4728e6SMichael S. Tsirkin         DeviceState *qdev = kid->child;
163*db4728e6SMichael S. Tsirkin         PCIDevice *pdev = PCI_DEVICE(qdev);
164*db4728e6SMichael S. Tsirkin         int slot = PCI_SLOT(pdev->devfn);
165*db4728e6SMichael S. Tsirkin 
166*db4728e6SMichael S. Tsirkin         if (acpi_pcihp_pc_no_hotplug(s, pdev)) {
167*db4728e6SMichael S. Tsirkin             s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot);
168*db4728e6SMichael S. Tsirkin         }
169*db4728e6SMichael S. Tsirkin 
170*db4728e6SMichael S. Tsirkin         s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
171*db4728e6SMichael S. Tsirkin     }
172*db4728e6SMichael S. Tsirkin }
173*db4728e6SMichael S. Tsirkin 
174*db4728e6SMichael S. Tsirkin static void acpi_pcihp_update(AcpiPciHpState *s)
175*db4728e6SMichael S. Tsirkin {
176*db4728e6SMichael S. Tsirkin     int i;
177*db4728e6SMichael S. Tsirkin 
178*db4728e6SMichael S. Tsirkin     for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) {
179*db4728e6SMichael S. Tsirkin         acpi_pcihp_update_hotplug_bus(s, i);
180*db4728e6SMichael S. Tsirkin     }
181*db4728e6SMichael S. Tsirkin }
182*db4728e6SMichael S. Tsirkin 
183*db4728e6SMichael S. Tsirkin void acpi_pcihp_reset(AcpiPciHpState *s)
184*db4728e6SMichael S. Tsirkin {
185*db4728e6SMichael S. Tsirkin     acpi_pcihp_update(s);
186*db4728e6SMichael S. Tsirkin }
187*db4728e6SMichael S. Tsirkin 
188*db4728e6SMichael S. Tsirkin static void enable_device(AcpiPciHpState *s, unsigned bsel, int slot)
189*db4728e6SMichael S. Tsirkin {
190*db4728e6SMichael S. Tsirkin     s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
191*db4728e6SMichael S. Tsirkin }
192*db4728e6SMichael S. Tsirkin 
193*db4728e6SMichael S. Tsirkin static void disable_device(AcpiPciHpState *s, unsigned bsel, int slot)
194*db4728e6SMichael S. Tsirkin {
195*db4728e6SMichael S. Tsirkin     s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
196*db4728e6SMichael S. Tsirkin }
197*db4728e6SMichael S. Tsirkin 
198*db4728e6SMichael S. Tsirkin int acpi_pcihp_device_hotplug(AcpiPciHpState *s, PCIDevice *dev,
199*db4728e6SMichael S. Tsirkin                               PCIHotplugState state)
200*db4728e6SMichael S. Tsirkin {
201*db4728e6SMichael S. Tsirkin     int slot = PCI_SLOT(dev->devfn);
202*db4728e6SMichael S. Tsirkin     int bsel = acpi_pcihp_get_bsel(dev->bus);
203*db4728e6SMichael S. Tsirkin     if (bsel < 0) {
204*db4728e6SMichael S. Tsirkin         return -1;
205*db4728e6SMichael S. Tsirkin     }
206*db4728e6SMichael S. Tsirkin 
207*db4728e6SMichael S. Tsirkin     /* Don't send event when device is enabled during qemu machine creation:
208*db4728e6SMichael S. Tsirkin      * it is present on boot, no hotplug event is necessary. We do send an
209*db4728e6SMichael S. Tsirkin      * event when the device is disabled later. */
210*db4728e6SMichael S. Tsirkin     if (state == PCI_COLDPLUG_ENABLED) {
211*db4728e6SMichael S. Tsirkin         s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
212*db4728e6SMichael S. Tsirkin         return 0;
213*db4728e6SMichael S. Tsirkin     }
214*db4728e6SMichael S. Tsirkin 
215*db4728e6SMichael S. Tsirkin     if (state == PCI_HOTPLUG_ENABLED) {
216*db4728e6SMichael S. Tsirkin         enable_device(s, bsel, slot);
217*db4728e6SMichael S. Tsirkin     } else {
218*db4728e6SMichael S. Tsirkin         disable_device(s, bsel, slot);
219*db4728e6SMichael S. Tsirkin     }
220*db4728e6SMichael S. Tsirkin 
221*db4728e6SMichael S. Tsirkin     return 0;
222*db4728e6SMichael S. Tsirkin }
223*db4728e6SMichael S. Tsirkin 
224*db4728e6SMichael S. Tsirkin static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
225*db4728e6SMichael S. Tsirkin {
226*db4728e6SMichael S. Tsirkin     AcpiPciHpState *s = opaque;
227*db4728e6SMichael S. Tsirkin     uint32_t val = 0;
228*db4728e6SMichael S. Tsirkin     int bsel = s->hotplug_select;
229*db4728e6SMichael S. Tsirkin 
230*db4728e6SMichael S. Tsirkin     if (bsel < 0 || bsel > ACPI_PCIHP_MAX_HOTPLUG_BUS) {
231*db4728e6SMichael S. Tsirkin         return 0;
232*db4728e6SMichael S. Tsirkin     }
233*db4728e6SMichael S. Tsirkin 
234*db4728e6SMichael S. Tsirkin     switch (addr) {
235*db4728e6SMichael S. Tsirkin     case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
236*db4728e6SMichael S. Tsirkin         /* Manufacture an "up" value to cause a device check on any hotplug
237*db4728e6SMichael S. Tsirkin          * slot with a device.  Extra device checks are harmless. */
238*db4728e6SMichael S. Tsirkin         val = s->acpi_pcihp_pci_status[bsel].device_present &
239*db4728e6SMichael S. Tsirkin             s->acpi_pcihp_pci_status[bsel].hotplug_enable;
240*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
241*db4728e6SMichael S. Tsirkin         break;
242*db4728e6SMichael S. Tsirkin     case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
243*db4728e6SMichael S. Tsirkin         val = s->acpi_pcihp_pci_status[bsel].down;
244*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val);
245*db4728e6SMichael S. Tsirkin         break;
246*db4728e6SMichael S. Tsirkin     case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
247*db4728e6SMichael S. Tsirkin         /* No feature defined yet */
248*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val);
249*db4728e6SMichael S. Tsirkin         break;
250*db4728e6SMichael S. Tsirkin     case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
251*db4728e6SMichael S. Tsirkin         val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
252*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val);
253*db4728e6SMichael S. Tsirkin         break;
254*db4728e6SMichael S. Tsirkin     case PCI_SEL_BASE - PCI_HOTPLUG_ADDR:
255*db4728e6SMichael S. Tsirkin         val = s->hotplug_select;
256*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val);
257*db4728e6SMichael S. Tsirkin     default:
258*db4728e6SMichael S. Tsirkin         break;
259*db4728e6SMichael S. Tsirkin     }
260*db4728e6SMichael S. Tsirkin 
261*db4728e6SMichael S. Tsirkin     return val;
262*db4728e6SMichael S. Tsirkin }
263*db4728e6SMichael S. Tsirkin 
264*db4728e6SMichael S. Tsirkin static void pci_write(void *opaque, hwaddr addr, uint64_t data,
265*db4728e6SMichael S. Tsirkin                       unsigned int size)
266*db4728e6SMichael S. Tsirkin {
267*db4728e6SMichael S. Tsirkin     AcpiPciHpState *s = opaque;
268*db4728e6SMichael S. Tsirkin     switch (addr) {
269*db4728e6SMichael S. Tsirkin     case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
270*db4728e6SMichael S. Tsirkin         if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
271*db4728e6SMichael S. Tsirkin             break;
272*db4728e6SMichael S. Tsirkin         }
273*db4728e6SMichael S. Tsirkin         acpi_pcihp_eject_slot(s, s->hotplug_select, data);
274*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
275*db4728e6SMichael S. Tsirkin                       addr, data);
276*db4728e6SMichael S. Tsirkin         break;
277*db4728e6SMichael S. Tsirkin     case PCI_SEL_BASE - PCI_HOTPLUG_ADDR:
278*db4728e6SMichael S. Tsirkin         s->hotplug_select = data;
279*db4728e6SMichael S. Tsirkin         ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n",
280*db4728e6SMichael S. Tsirkin                       addr, data);
281*db4728e6SMichael S. Tsirkin     default:
282*db4728e6SMichael S. Tsirkin         break;
283*db4728e6SMichael S. Tsirkin     }
284*db4728e6SMichael S. Tsirkin }
285*db4728e6SMichael S. Tsirkin 
286*db4728e6SMichael S. Tsirkin static const MemoryRegionOps acpi_pcihp_io_ops = {
287*db4728e6SMichael S. Tsirkin     .read = pci_read,
288*db4728e6SMichael S. Tsirkin     .write = pci_write,
289*db4728e6SMichael S. Tsirkin     .endianness = DEVICE_LITTLE_ENDIAN,
290*db4728e6SMichael S. Tsirkin     .valid = {
291*db4728e6SMichael S. Tsirkin         .min_access_size = 4,
292*db4728e6SMichael S. Tsirkin         .max_access_size = 4,
293*db4728e6SMichael S. Tsirkin     },
294*db4728e6SMichael S. Tsirkin };
295*db4728e6SMichael S. Tsirkin 
296*db4728e6SMichael S. Tsirkin void acpi_pcihp_init(AcpiPciHpState *s, PCIBus *root_bus,
297*db4728e6SMichael S. Tsirkin                      MemoryRegion *address_space_io)
298*db4728e6SMichael S. Tsirkin {
299*db4728e6SMichael S. Tsirkin     s->root= root_bus;
300*db4728e6SMichael S. Tsirkin     memory_region_init_io(&s->io, NULL, &acpi_pcihp_io_ops, s,
301*db4728e6SMichael S. Tsirkin                           "acpi-pci-hotplug",
302*db4728e6SMichael S. Tsirkin                           PCI_HOTPLUG_SIZE);
303*db4728e6SMichael S. Tsirkin     memory_region_add_subregion(address_space_io, PCI_HOTPLUG_ADDR, &s->io);
304*db4728e6SMichael S. Tsirkin }
305*db4728e6SMichael S. Tsirkin 
306*db4728e6SMichael S. Tsirkin const VMStateDescription vmstate_acpi_pcihp_pci_status = {
307*db4728e6SMichael S. Tsirkin     .name = "acpi_pcihp_pci_status",
308*db4728e6SMichael S. Tsirkin     .version_id = 1,
309*db4728e6SMichael S. Tsirkin     .minimum_version_id = 1,
310*db4728e6SMichael S. Tsirkin     .minimum_version_id_old = 1,
311*db4728e6SMichael S. Tsirkin     .fields      = (VMStateField []) {
312*db4728e6SMichael S. Tsirkin         VMSTATE_UINT32(up, AcpiPciHpPciStatus),
313*db4728e6SMichael S. Tsirkin         VMSTATE_UINT32(down, AcpiPciHpPciStatus),
314*db4728e6SMichael S. Tsirkin         VMSTATE_END_OF_LIST()
315*db4728e6SMichael S. Tsirkin     }
316*db4728e6SMichael S. Tsirkin };
317