| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU<->ACPI BIOS PCI hotplug interface | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * QEMU supports PCI hotplug via ACPI. This module | 
					
						
							|  |  |  |  * implements the interface between QEMU and the ACPI BIOS. | 
					
						
							|  |  |  |  * Interface specification - see docs/specs/acpi_pci_hotplug.txt | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com) | 
					
						
							|  |  |  |  * Copyright (c) 2006 Fabrice Bellard | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License version 2 as published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License along with this library; if not, see <http://www.gnu.org/licenses/>
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributions after 2012-01-13 are licensed under the terms of the | 
					
						
							|  |  |  |  * GNU GPL, version 2 or (at your option) any later version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:03 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | #include "hw/acpi/pcihp.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hw/hw.h"
 | 
					
						
							|  |  |  | #include "hw/i386/pc.h"
 | 
					
						
							|  |  |  | #include "hw/pci/pci.h"
 | 
					
						
							|  |  |  | #include "hw/acpi/acpi.h"
 | 
					
						
							|  |  |  | #include "sysemu/sysemu.h"
 | 
					
						
							|  |  |  | #include "exec/ioport.h"
 | 
					
						
							|  |  |  | #include "exec/address-spaces.h"
 | 
					
						
							|  |  |  | #include "hw/pci/pci_bus.h"
 | 
					
						
							| 
									
										
											  
											
												include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef.  Since then, we've moved to include qemu/osdep.h
everywhere.  Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h.  That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h.  Include qapi/error.h in .c files that need it and don't
get it now.  Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly.  Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h.  Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third.  Unfortunately, the number depending on
qapi-types.h shrinks only a little.  More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
											
										 
											2016-03-14 09:01:28 +01:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | #include "qom/qom-qobject.h"
 | 
					
						
							|  |  |  | #include "qapi/qmp/qint.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //#define DEBUG
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef DEBUG
 | 
					
						
							|  |  |  | # define ACPI_PCIHP_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | # define ACPI_PCIHP_DPRINTF(format, ...)     do { } while (0)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 11:45:01 +01:00
										 |  |  | #define ACPI_PCIHP_ADDR 0xae00
 | 
					
						
							|  |  |  | #define ACPI_PCIHP_SIZE 0x0014
 | 
					
						
							|  |  |  | #define ACPI_PCIHP_LEGACY_SIZE 0x000f
 | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  | #define PCI_UP_BASE 0x0000
 | 
					
						
							|  |  |  | #define PCI_DOWN_BASE 0x0004
 | 
					
						
							|  |  |  | #define PCI_EJ_BASE 0x0008
 | 
					
						
							|  |  |  | #define PCI_RMV_BASE 0x000c
 | 
					
						
							|  |  |  | #define PCI_SEL_BASE 0x0010
 | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct AcpiPciHpFind { | 
					
						
							|  |  |  |     int bsel; | 
					
						
							|  |  |  |     PCIBus *bus; | 
					
						
							|  |  |  | } AcpiPciHpFind; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int acpi_pcihp_get_bsel(PCIBus *bus) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-04-24 18:15:56 +04:00
										 |  |  |     Error *local_err = NULL; | 
					
						
							|  |  |  |     int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, | 
					
						
							|  |  |  |                                            &local_err); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { | 
					
						
							|  |  |  |         if (local_err) { | 
					
						
							|  |  |  |             error_free(local_err); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2014-04-24 18:15:56 +04:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         return bsel; | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AcpiPciHpFind *find = opaque; | 
					
						
							|  |  |  |     if (find->bsel == acpi_pcihp_get_bsel(bus)) { | 
					
						
							|  |  |  |         find->bus = bus; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AcpiPciHpFind find = { .bsel = bsel, .bus = NULL }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bsel < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Make bsel 0 eject root bus if bsel property is not set,
 | 
					
						
							|  |  |  |      * for compatibility with non acpi setups. | 
					
						
							|  |  |  |      * TODO: really needed? | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (!bsel && !find.bus) { | 
					
						
							|  |  |  |         find.bus = s->root; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return find.bus; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:48 +01:00
										 |  |  |     DeviceClass *dc = DEVICE_GET_CLASS(dev); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |      * ACPI doesn't allow hotplug of bridge devices.  Don't allow | 
					
						
							|  |  |  |      * hot-unplug of bridge devices unless they were added by hotplug | 
					
						
							|  |  |  |      * (and so, not described by acpi). | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:48 +01:00
										 |  |  |     return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable; | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BusChild *kid, *next; | 
					
						
							| 
									
										
										
										
											2015-03-23 15:29:26 +00:00
										 |  |  |     int slot = ctz32(slots); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!bus) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Mark request as complete */ | 
					
						
							|  |  |  |     s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot); | 
					
						
							| 
									
										
										
										
											2014-01-26 12:31:27 +02:00
										 |  |  |     s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { | 
					
						
							|  |  |  |         DeviceState *qdev = kid->child; | 
					
						
							|  |  |  |         PCIDevice *dev = PCI_DEVICE(qdev); | 
					
						
							|  |  |  |         if (PCI_SLOT(dev->devfn) == slot) { | 
					
						
							| 
									
										
										
										
											2014-01-26 12:31:27 +02:00
										 |  |  |             if (!acpi_pcihp_pc_no_hotplug(s, dev)) { | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |                 object_unparent(OBJECT(qdev)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BusChild *kid, *next; | 
					
						
							|  |  |  |     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Execute any pending removes during reset */ | 
					
						
							|  |  |  |     while (s->acpi_pcihp_pci_status[bsel].down) { | 
					
						
							|  |  |  |         acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!bus) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { | 
					
						
							|  |  |  |         DeviceState *qdev = kid->child; | 
					
						
							|  |  |  |         PCIDevice *pdev = PCI_DEVICE(qdev); | 
					
						
							|  |  |  |         int slot = PCI_SLOT(pdev->devfn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (acpi_pcihp_pc_no_hotplug(s, pdev)) { | 
					
						
							|  |  |  |             s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void acpi_pcihp_update(AcpiPciHpState *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) { | 
					
						
							|  |  |  |         acpi_pcihp_update_hotplug_bus(s, i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void acpi_pcihp_reset(AcpiPciHpState *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     acpi_pcihp_update(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:01:17 +02:00
										 |  |  | void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |                                DeviceState *dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |     PCIDevice *pdev = PCI_DEVICE(dev); | 
					
						
							|  |  |  |     int slot = PCI_SLOT(pdev->devfn); | 
					
						
							|  |  |  |     int bsel = acpi_pcihp_get_bsel(pdev->bus); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     if (bsel < 0) { | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |         error_setg(errp, "Unsupported bus. Bus doesn't have property '" | 
					
						
							|  |  |  |                    ACPI_PCIHP_PROP_BSEL "' set"); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Don't send event when device is enabled during qemu machine creation:
 | 
					
						
							|  |  |  |      * it is present on boot, no hotplug event is necessary. We do send an | 
					
						
							|  |  |  |      * event when the device is disabled later. */ | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |     if (!dev->hotplugged) { | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |     s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); | 
					
						
							| 
									
										
										
										
											2016-05-31 12:01:17 +02:00
										 |  |  |     acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 12:01:17 +02:00
										 |  |  | void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |                                  DeviceState *dev, Error **errp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *pdev = PCI_DEVICE(dev); | 
					
						
							|  |  |  |     int slot = PCI_SLOT(pdev->devfn); | 
					
						
							|  |  |  |     int bsel = acpi_pcihp_get_bsel(pdev->bus); | 
					
						
							|  |  |  |     if (bsel < 0) { | 
					
						
							|  |  |  |         error_setg(errp, "Unsupported bus. Bus doesn't have property '" | 
					
						
							|  |  |  |                    ACPI_PCIHP_PROP_BSEL "' set"); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 16:36:49 +01:00
										 |  |  |     s->acpi_pcihp_pci_status[bsel].down |= (1U << slot); | 
					
						
							| 
									
										
										
										
											2016-05-31 12:01:17 +02:00
										 |  |  |     acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AcpiPciHpState *s = opaque; | 
					
						
							|  |  |  |     uint32_t val = 0; | 
					
						
							|  |  |  |     int bsel = s->hotplug_select; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-20 13:52:30 +08:00
										 |  |  |     if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_UP_BASE: | 
					
						
							| 
									
										
										
										
											2014-01-26 12:31:27 +02:00
										 |  |  |         val = s->acpi_pcihp_pci_status[bsel].up; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:59 +01:00
										 |  |  |         if (!s->legacy_piix) { | 
					
						
							|  |  |  |             s->acpi_pcihp_pci_status[bsel].up = 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_DOWN_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         val = s->acpi_pcihp_pci_status[bsel].down; | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_EJ_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         /* No feature defined yet */ | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_RMV_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         val = s->acpi_pcihp_pci_status[bsel].hotplug_enable; | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_SEL_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         val = s->hotplug_select; | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pci_write(void *opaque, hwaddr addr, uint64_t data, | 
					
						
							|  |  |  |                       unsigned int size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AcpiPciHpState *s = opaque; | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_EJ_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         acpi_pcihp_eject_slot(s, s->hotplug_select, data); | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n", | 
					
						
							|  |  |  |                       addr, data); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:58 +01:00
										 |  |  |     case PCI_SEL_BASE: | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         s->hotplug_select = data; | 
					
						
							|  |  |  |         ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n", | 
					
						
							|  |  |  |                       addr, data); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const MemoryRegionOps acpi_pcihp_io_ops = { | 
					
						
							|  |  |  |     .read = pci_read, | 
					
						
							|  |  |  |     .write = pci_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_LITTLE_ENDIAN, | 
					
						
							|  |  |  |     .valid = { | 
					
						
							|  |  |  |         .min_access_size = 4, | 
					
						
							|  |  |  |         .max_access_size = 4, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-18 19:14:49 +00:00
										 |  |  | void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:59 +01:00
										 |  |  |                      MemoryRegion *address_space_io, bool bridges_enabled) | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-02-18 19:14:49 +00:00
										 |  |  |     s->io_len = ACPI_PCIHP_SIZE; | 
					
						
							|  |  |  |     s->io_base = ACPI_PCIHP_ADDR; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |     s->root= root_bus; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:44:59 +01:00
										 |  |  |     s->legacy_piix = !bridges_enabled; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (s->legacy_piix) { | 
					
						
							|  |  |  |         unsigned *bus_bsel = g_malloc(sizeof *bus_bsel); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-18 19:14:49 +00:00
										 |  |  |         s->io_len = ACPI_PCIHP_LEGACY_SIZE; | 
					
						
							| 
									
										
										
										
											2014-02-03 11:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         *bus_bsel = ACPI_PCIHP_BSEL_DEFAULT; | 
					
						
							|  |  |  |         object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL, | 
					
						
							|  |  |  |                                        bus_bsel, NULL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-18 19:14:49 +00:00
										 |  |  |     memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s, | 
					
						
							|  |  |  |                           "acpi-pci-hotplug", s->io_len); | 
					
						
							|  |  |  |     memory_region_add_subregion(address_space_io, s->io_base, &s->io); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_BASE_PROP, &s->io_base, | 
					
						
							|  |  |  |                                    &error_abort); | 
					
						
							|  |  |  |     object_property_add_uint16_ptr(owner, ACPI_PCIHP_IO_LEN_PROP, &s->io_len, | 
					
						
							|  |  |  |                                    &error_abort); | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const VMStateDescription vmstate_acpi_pcihp_pci_status = { | 
					
						
							|  |  |  |     .name = "acpi_pcihp_pci_status", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							| 
									
										
										
										
											2014-04-16 15:32:32 +02:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2013-10-14 18:01:11 +03:00
										 |  |  |         VMSTATE_UINT32(up, AcpiPciHpPciStatus), | 
					
						
							|  |  |  |         VMSTATE_UINT32(down, AcpiPciHpPciStatus), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; |