xref: /openbmc/qemu/hw/acpi/pcihp.c (revision d4842052100a3b44167e34ebdce0e7b3bf7512cf)
1 /*
2  * QEMU<->ACPI BIOS PCI hotplug interface
3  *
4  * QEMU supports PCI hotplug via ACPI. This module
5  * implements the interface between QEMU and the ACPI BIOS.
6  * Interface specification - see docs/specs/acpi_pci_hotplug.txt
7  *
8  * Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
9  * Copyright (c) 2006 Fabrice Bellard
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License version 2 as published by the Free Software Foundation.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, see <http://www.gnu.org/licenses/>
22  *
23  * Contributions after 2012-01-13 are licensed under the terms of the
24  * GNU GPL, version 2 or (at your option) any later version.
25  */
26 
27 #include "qemu/osdep.h"
28 #include "hw/acpi/pcihp.h"
29 
30 #include "hw/hw.h"
31 #include "hw/i386/pc.h"
32 #include "hw/pci/pci.h"
33 #include "hw/pci/pci_bridge.h"
34 #include "hw/acpi/acpi.h"
35 #include "sysemu/sysemu.h"
36 #include "exec/address-spaces.h"
37 #include "hw/pci/pci_bus.h"
38 #include "migration/vmstate.h"
39 #include "qapi/error.h"
40 #include "qom/qom-qobject.h"
41 #include "trace.h"
42 
43 #define ACPI_PCIHP_ADDR 0xae00
44 #define ACPI_PCIHP_SIZE 0x0014
45 #define PCI_UP_BASE 0x0000
46 #define PCI_DOWN_BASE 0x0004
47 #define PCI_EJ_BASE 0x0008
48 #define PCI_RMV_BASE 0x000c
49 #define PCI_SEL_BASE 0x0010
50 
51 typedef struct AcpiPciHpFind {
52     int bsel;
53     PCIBus *bus;
54 } AcpiPciHpFind;
55 
56 static int acpi_pcihp_get_bsel(PCIBus *bus)
57 {
58     Error *local_err = NULL;
59     uint64_t bsel = object_property_get_uint(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
60                                              &local_err);
61 
62     if (local_err || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
63         if (local_err) {
64             error_free(local_err);
65         }
66         return -1;
67     } else {
68         return bsel;
69     }
70 }
71 
72 /* Assign BSEL property to all buses.  In the future, this can be changed
73  * to only assign to buses that support hotplug.
74  */
75 static void *acpi_set_bsel(PCIBus *bus, void *opaque)
76 {
77     unsigned *bsel_alloc = opaque;
78     unsigned *bus_bsel;
79 
80     if (qbus_is_hotpluggable(BUS(bus))) {
81         bus_bsel = g_malloc(sizeof *bus_bsel);
82 
83         *bus_bsel = (*bsel_alloc)++;
84         object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
85                                        bus_bsel, &error_abort);
86     }
87 
88     return bsel_alloc;
89 }
90 
91 static void acpi_set_pci_info(void)
92 {
93     static bool bsel_is_set;
94     PCIBus *bus;
95     unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT;
96 
97     if (bsel_is_set) {
98         return;
99     }
100     bsel_is_set = true;
101 
102     bus = find_i440fx(); /* TODO: Q35 support */
103     if (bus) {
104         /* Scan all PCI buses. Set property to enable acpi based hotplug. */
105         pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
106     }
107 }
108 
109 static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
110 {
111     AcpiPciHpFind *find = opaque;
112     if (find->bsel == acpi_pcihp_get_bsel(bus)) {
113         find->bus = bus;
114     }
115 }
116 
117 static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel)
118 {
119     AcpiPciHpFind find = { .bsel = bsel, .bus = NULL };
120 
121     if (bsel < 0) {
122         return NULL;
123     }
124 
125     pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find);
126 
127     /* Make bsel 0 eject root bus if bsel property is not set,
128      * for compatibility with non acpi setups.
129      * TODO: really needed?
130      */
131     if (!bsel && !find.bus) {
132         find.bus = s->root;
133     }
134     return find.bus;
135 }
136 
137 static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
138 {
139     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
140     DeviceClass *dc = DEVICE_GET_CLASS(dev);
141     /*
142      * ACPI doesn't allow hotplug of bridge devices.  Don't allow
143      * hot-unplug of bridge devices unless they were added by hotplug
144      * (and so, not described by acpi).
145      */
146     return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable;
147 }
148 
149 static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
150 {
151     HotplugHandler *hotplug_ctrl;
152     BusChild *kid, *next;
153     int slot = ctz32(slots);
154     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
155 
156     trace_acpi_pci_eject_slot(bsel, slot);
157 
158     if (!bus) {
159         return;
160     }
161 
162     /* Mark request as complete */
163     s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot);
164     s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot);
165 
166     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
167         DeviceState *qdev = kid->child;
168         PCIDevice *dev = PCI_DEVICE(qdev);
169         if (PCI_SLOT(dev->devfn) == slot) {
170             if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
171                 hotplug_ctrl = qdev_get_hotplug_handler(qdev);
172                 hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
173                 object_unparent(OBJECT(qdev));
174             }
175         }
176     }
177 }
178 
179 static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
180 {
181     BusChild *kid, *next;
182     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
183 
184     /* Execute any pending removes during reset */
185     while (s->acpi_pcihp_pci_status[bsel].down) {
186         acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down);
187     }
188 
189     s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0;
190 
191     if (!bus) {
192         return;
193     }
194     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
195         DeviceState *qdev = kid->child;
196         PCIDevice *pdev = PCI_DEVICE(qdev);
197         int slot = PCI_SLOT(pdev->devfn);
198 
199         if (acpi_pcihp_pc_no_hotplug(s, pdev)) {
200             s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot);
201         }
202     }
203 }
204 
205 static void acpi_pcihp_update(AcpiPciHpState *s)
206 {
207     int i;
208 
209     for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) {
210         acpi_pcihp_update_hotplug_bus(s, i);
211     }
212 }
213 
214 void acpi_pcihp_reset(AcpiPciHpState *s)
215 {
216     acpi_set_pci_info();
217     acpi_pcihp_update(s);
218 }
219 
220 void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
221                                    DeviceState *dev, Error **errp)
222 {
223     /* Only hotplugged devices need the hotplug capability. */
224     if (dev->hotplugged &&
225         acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))) < 0) {
226         error_setg(errp, "Unsupported bus. Bus doesn't have property '"
227                    ACPI_PCIHP_PROP_BSEL "' set");
228         return;
229     }
230 }
231 
232 void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
233                                DeviceState *dev, Error **errp)
234 {
235     PCIDevice *pdev = PCI_DEVICE(dev);
236     int slot = PCI_SLOT(pdev->devfn);
237     int bsel;
238 
239     /* Don't send event when device is enabled during qemu machine creation:
240      * it is present on boot, no hotplug event is necessary. We do send an
241      * event when the device is disabled later. */
242     if (!dev->hotplugged) {
243         /*
244          * Overwrite the default hotplug handler with the ACPI PCI one
245          * for cold plugged bridges only.
246          */
247         if (!s->legacy_piix &&
248             object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
249             PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
250 
251             qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev),
252                                      &error_abort);
253             /* We don't have to overwrite any other hotplug handler yet */
254             assert(QLIST_EMPTY(&sec->child));
255         }
256 
257         return;
258     }
259 
260     bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
261     g_assert(bsel >= 0);
262     s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
263     acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
264 }
265 
266 void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
267                                  DeviceState *dev, Error **errp)
268 {
269     trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn),
270                           acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))));
271     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
272 }
273 
274 void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
275                                          AcpiPciHpState *s, DeviceState *dev,
276                                          Error **errp)
277 {
278     PCIDevice *pdev = PCI_DEVICE(dev);
279     int slot = PCI_SLOT(pdev->devfn);
280     int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
281 
282     trace_acpi_pci_unplug_request(bsel, slot);
283 
284     if (bsel < 0) {
285         error_setg(errp, "Unsupported bus. Bus doesn't have property '"
286                    ACPI_PCIHP_PROP_BSEL "' set");
287         return;
288     }
289 
290     s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
291     acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
292 }
293 
294 static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
295 {
296     AcpiPciHpState *s = opaque;
297     uint32_t val = 0;
298     int bsel = s->hotplug_select;
299 
300     if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
301         return 0;
302     }
303 
304     switch (addr) {
305     case PCI_UP_BASE:
306         val = s->acpi_pcihp_pci_status[bsel].up;
307         if (!s->legacy_piix) {
308             s->acpi_pcihp_pci_status[bsel].up = 0;
309         }
310         trace_acpi_pci_up_read(val);
311         break;
312     case PCI_DOWN_BASE:
313         val = s->acpi_pcihp_pci_status[bsel].down;
314         trace_acpi_pci_down_read(val);
315         break;
316     case PCI_EJ_BASE:
317         /* No feature defined yet */
318         trace_acpi_pci_features_read(val);
319         break;
320     case PCI_RMV_BASE:
321         val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
322         trace_acpi_pci_rmv_read(val);
323         break;
324     case PCI_SEL_BASE:
325         val = s->hotplug_select;
326         trace_acpi_pci_sel_read(val);
327     default:
328         break;
329     }
330 
331     return val;
332 }
333 
334 static void pci_write(void *opaque, hwaddr addr, uint64_t data,
335                       unsigned int size)
336 {
337     AcpiPciHpState *s = opaque;
338     switch (addr) {
339     case PCI_EJ_BASE:
340         if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
341             break;
342         }
343         acpi_pcihp_eject_slot(s, s->hotplug_select, data);
344         trace_acpi_pci_ej_write(addr, data);
345         break;
346     case PCI_SEL_BASE:
347         s->hotplug_select = s->legacy_piix ? ACPI_PCIHP_BSEL_DEFAULT : data;
348         trace_acpi_pci_sel_write(addr, data);
349     default:
350         break;
351     }
352 }
353 
354 static const MemoryRegionOps acpi_pcihp_io_ops = {
355     .read = pci_read,
356     .write = pci_write,
357     .endianness = DEVICE_LITTLE_ENDIAN,
358     .valid = {
359         .min_access_size = 4,
360         .max_access_size = 4,
361     },
362 };
363 
364 void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
365                      MemoryRegion *address_space_io, bool bridges_enabled)
366 {
367     s->io_len = ACPI_PCIHP_SIZE;
368     s->io_base = ACPI_PCIHP_ADDR;
369 
370     s->root= root_bus;
371     s->legacy_piix = !bridges_enabled;
372 
373     memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s,
374                           "acpi-pci-hotplug", s->io_len);
375     memory_region_add_subregion(address_space_io, s->io_base, &s->io);
376 
377     object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base,
378                                    &error_abort);
379     object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_LEN_PROP, &s->io_len,
380                                    &error_abort);
381 }
382 
383 const VMStateDescription vmstate_acpi_pcihp_pci_status = {
384     .name = "acpi_pcihp_pci_status",
385     .version_id = 1,
386     .minimum_version_id = 1,
387     .fields = (VMStateField[]) {
388         VMSTATE_UINT32(up, AcpiPciHpPciStatus),
389         VMSTATE_UINT32(down, AcpiPciHpPciStatus),
390         VMSTATE_END_OF_LIST()
391     }
392 };
393