mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-10-14 15:02:54 +00:00
virtio, vhost, acpi: features, fixes, tests
ARM ACPI memory hotplug support + tests for new arm/virt ACPI tables. Virtio fs support (no migration). A vhost-user reconnect bugfix. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJdpjPbAAoJECgfDbjSjVRpQqUH/2xyT++y8K17mCI1IILLZd3d eOqElEHz78qlEfR2euv63YksZoeHpMO5HiAdwOGGF8CjcaCT4Hl+pPDffTYVXtt+ VZ88vSSXL49wpMcpvRGR5Isy0eXJzWilTBMu2eu8phN9tX82dlu08Oi4XGAosrBJ uZg61DyiGDnSOpoofHhjvXJEaiL0pzkTjf8qAoW3TaVcB9NQKnunMEIDD646JS5z AAj4+XBJfUG9cp7/MG+djjVmJDdUpjL5e5uWNWakbgUVqSbHog78RIrBoD6SH7pt /6hHHoSM9VX1wWgdTdVdNAQAZVnWs31w4v31d8UfaT15KJEoG47U0gDgmLzXDyo= =+xdg -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging virtio, vhost, acpi: features, fixes, tests ARM ACPI memory hotplug support + tests for new arm/virt ACPI tables. Virtio fs support (no migration). A vhost-user reconnect bugfix. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Tue 15 Oct 2019 22:02:19 BST # gpg: using RSA key 281F0DB8D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: virtio: add vhost-user-fs-pci device virtio: add vhost-user-fs base device virtio: Add virtio_fs linux headers tests/acpi: add expected tables for arm/virt tests: document how to update acpi tables tests: Add bios tests to arm/virt tests: allow empty expected files tests/acpi: add empty files tests: Update ACPI tables list for upcoming arm/virt tests docs/specs: Add ACPI GED documentation hw/arm: Use GED for system_powerdown event hw/arm: Factor out powerdown notifier from GPIO hw/arm/virt-acpi-build: Add PC-DIMM in SRAT hw/arm/virt: Enable device memory cold/hot plug with ACPI boot hw/arm/virt: Add memory hotplug framework hw/acpi: Add ACPI Generic Event Device Support hw/acpi: Do not create memory hotplug method when handler is not defined hw/acpi: Make ACPI IO address space configurable vhost-user: save features if the char dev is closed Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
39b68bc4f1
13
configure
vendored
13
configure
vendored
|
@ -381,6 +381,7 @@ vhost_crypto=""
|
|||
vhost_scsi=""
|
||||
vhost_vsock=""
|
||||
vhost_user=""
|
||||
vhost_user_fs=""
|
||||
kvm="no"
|
||||
hax="no"
|
||||
hvf="no"
|
||||
|
@ -1293,6 +1294,10 @@ for opt do
|
|||
;;
|
||||
--enable-vhost-vsock) vhost_vsock="yes"
|
||||
;;
|
||||
--disable-vhost-user-fs) vhost_user_fs="no"
|
||||
;;
|
||||
--enable-vhost-user-fs) vhost_user_fs="yes"
|
||||
;;
|
||||
--disable-opengl) opengl="no"
|
||||
;;
|
||||
--enable-opengl) opengl="yes"
|
||||
|
@ -2236,6 +2241,10 @@ test "$vhost_crypto" = "" && vhost_crypto=$vhost_user
|
|||
if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then
|
||||
error_exit "--enable-vhost-crypto requires --enable-vhost-user"
|
||||
fi
|
||||
test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user
|
||||
if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then
|
||||
error_exit "--enable-vhost-user-fs requires --enable-vhost-user"
|
||||
fi
|
||||
|
||||
# OR the vhost-kernel and vhost-user values for simplicity
|
||||
if test "$vhost_net" = ""; then
|
||||
|
@ -6374,6 +6383,7 @@ echo "vhost-crypto support $vhost_crypto"
|
|||
echo "vhost-scsi support $vhost_scsi"
|
||||
echo "vhost-vsock support $vhost_vsock"
|
||||
echo "vhost-user support $vhost_user"
|
||||
echo "vhost-user-fs support $vhost_user_fs"
|
||||
echo "Trace backends $trace_backends"
|
||||
if have_backend "simple"; then
|
||||
echo "Trace output file $trace_file-<pid>"
|
||||
|
@ -6870,6 +6880,9 @@ fi
|
|||
if test "$vhost_user" = "yes" ; then
|
||||
echo "CONFIG_VHOST_USER=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$vhost_user_fs" = "yes" ; then
|
||||
echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$blobs" = "yes" ; then
|
||||
echo "INSTALL_BLOBS=yes" >> $config_host_mak
|
||||
fi
|
||||
|
|
70
docs/specs/acpi_hw_reduced_hotplug.rst
Normal file
70
docs/specs/acpi_hw_reduced_hotplug.rst
Normal file
|
@ -0,0 +1,70 @@
|
|||
==================================================
|
||||
QEMU and ACPI BIOS Generic Event Device interface
|
||||
==================================================
|
||||
|
||||
The ACPI *Generic Event Device* (GED) is a HW reduced platform
|
||||
specific device introduced in ACPI v6.1 that handles all platform
|
||||
events, including the hotplug ones. GED is modelled as a device
|
||||
in the namespace with a _HID defined to be ACPI0013. This document
|
||||
describes the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
GED allows HW reduced platforms to handle interrupts in ACPI ASL
|
||||
statements. It follows a very similar approach to the _EVT method
|
||||
from GPIO events. All interrupts are listed in _CRS and the handler
|
||||
is written in _EVT method. However, the QEMU implementation uses a
|
||||
single interrupt for the GED device, relying on an IO memory region
|
||||
to communicate the type of device affected by the interrupt. This way,
|
||||
we can support up to 32 events with a unique interrupt.
|
||||
|
||||
**Here is an example,**
|
||||
|
||||
::
|
||||
|
||||
Device (\_SB.GED)
|
||||
{
|
||||
Name (_HID, "ACPI0013")
|
||||
Name (_UID, Zero)
|
||||
Name (_CRS, ResourceTemplate ()
|
||||
{
|
||||
Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
|
||||
{
|
||||
0x00000029,
|
||||
}
|
||||
})
|
||||
OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
|
||||
Field (EREG, DWordAcc, NoLock, WriteAsZeros)
|
||||
{
|
||||
ESEL, 32
|
||||
}
|
||||
Method (_EVT, 1, Serialized)
|
||||
{
|
||||
Local0 = ESEL // ESEL = IO memory region which specifies the
|
||||
// device type.
|
||||
If (((Local0 & One) == One))
|
||||
{
|
||||
MethodEvent1()
|
||||
}
|
||||
If ((Local0 & 0x2) == 0x2)
|
||||
{
|
||||
MethodEvent2()
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
GED IO interface (4 byte access)
|
||||
--------------------------------
|
||||
**read access:**
|
||||
|
||||
::
|
||||
|
||||
[0x0-0x3] Event selector bit field (32 bit) set by QEMU.
|
||||
|
||||
bits:
|
||||
0: Memory hotplug event
|
||||
1: System power down event
|
||||
2-31: Reserved
|
||||
|
||||
**write_access:**
|
||||
|
||||
Nothing is expected to be written into GED IO memory
|
|
@ -12,3 +12,4 @@ Contents:
|
|||
|
||||
ppc-xive
|
||||
ppc-spapr-xive
|
||||
acpi_hw_reduced_hotplug
|
||||
|
|
|
@ -31,3 +31,7 @@ config ACPI_VMGENID
|
|||
bool
|
||||
default y
|
||||
depends on PC
|
||||
|
||||
config ACPI_HW_REDUCED
|
||||
bool
|
||||
depends on ACPI
|
||||
|
|
|
@ -6,6 +6,7 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
|||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
|
||||
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
|
||||
common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
|
||||
common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o
|
||||
common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
|
||||
|
||||
common-obj-y += acpi_interface.o
|
||||
|
|
311
hw/acpi/generic_event_device.c
Normal file
311
hw/acpi/generic_event_device.c
Normal file
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
|
||||
* Written by Samuel Ortiz, Shameer Kolothum
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
static const uint32_t ged_supported_events[] = {
|
||||
ACPI_GED_MEM_HOTPLUG_EVT,
|
||||
ACPI_GED_PWR_DOWN_EVT,
|
||||
};
|
||||
|
||||
/*
|
||||
* The ACPI Generic Event Device (GED) is a hardware-reduced specific
|
||||
* device[ACPI v6.1 Section 5.6.9] that handles all platform events,
|
||||
* including the hotplug ones. Platforms need to specify their own
|
||||
* GED Event bitmap to describe what kind of events they want to support
|
||||
* through GED. This routine uses a single interrupt for the GED device,
|
||||
* relying on IO memory region to communicate the type of device
|
||||
* affected by the interrupt. This way, we can support up to 32 events
|
||||
* with a unique interrupt.
|
||||
*/
|
||||
void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
|
||||
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
|
||||
{
|
||||
AcpiGedState *s = ACPI_GED(hotplug_dev);
|
||||
Aml *crs = aml_resource_template();
|
||||
Aml *evt, *field;
|
||||
Aml *dev = aml_device("%s", name);
|
||||
Aml *evt_sel = aml_local(0);
|
||||
Aml *esel = aml_name(AML_GED_EVT_SEL);
|
||||
|
||||
/* _CRS interrupt */
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
|
||||
AML_EXCLUSIVE, &ged_irq, 1));
|
||||
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE)));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
/* Append IO region */
|
||||
aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs,
|
||||
aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET),
|
||||
ACPI_GED_EVT_SEL_LEN));
|
||||
field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK,
|
||||
AML_WRITE_AS_ZEROS);
|
||||
aml_append(field, aml_named_field(AML_GED_EVT_SEL,
|
||||
ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE));
|
||||
aml_append(dev, field);
|
||||
|
||||
/*
|
||||
* For each GED event we:
|
||||
* - Add a conditional block for each event, inside a loop.
|
||||
* - Call a method for each supported GED event type.
|
||||
*
|
||||
* The resulting ASL code looks like:
|
||||
*
|
||||
* Local0 = ESEL
|
||||
* If ((Local0 & One) == One)
|
||||
* {
|
||||
* MethodEvent0()
|
||||
* }
|
||||
*
|
||||
* If ((Local0 & 0x2) == 0x2)
|
||||
* {
|
||||
* MethodEvent1()
|
||||
* }
|
||||
* ...
|
||||
*/
|
||||
evt = aml_method("_EVT", 1, AML_SERIALIZED);
|
||||
{
|
||||
Aml *if_ctx;
|
||||
uint32_t i;
|
||||
uint32_t ged_events = ctpop32(s->ged_event_bitmap);
|
||||
|
||||
/* Local0 = ESEL */
|
||||
aml_append(evt, aml_store(esel, evt_sel));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
|
||||
uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
|
||||
|
||||
if (!event) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL),
|
||||
aml_int(event)));
|
||||
switch (event) {
|
||||
case ACPI_GED_MEM_HOTPLUG_EVT:
|
||||
aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
|
||||
MEMORY_SLOT_SCAN_METHOD));
|
||||
break;
|
||||
case ACPI_GED_PWR_DOWN_EVT:
|
||||
aml_append(if_ctx,
|
||||
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
|
||||
aml_int(0x80)));
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Please make sure all the events in ged_supported_events[]
|
||||
* are handled above.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
aml_append(evt, if_ctx);
|
||||
ged_events--;
|
||||
}
|
||||
|
||||
if (ged_events) {
|
||||
error_report("Unsupported events specified");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Append _EVT method */
|
||||
aml_append(dev, evt);
|
||||
|
||||
aml_append(table, dev);
|
||||
}
|
||||
|
||||
/* Memory read by the GED _EVT AML dynamic method */
|
||||
static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
GEDState *ged_st = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case ACPI_GED_EVT_SEL_OFFSET:
|
||||
/* Read the selector value and reset it */
|
||||
val = ged_st->sel;
|
||||
ged_st->sel = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Nothing is expected to be written to the GED memory region */
|
||||
static void ged_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ged_ops = {
|
||||
.read = ged_read,
|
||||
.write = ged_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
AcpiGedState *s = ACPI_GED(hotplug_dev);
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "virt: device plug request for unsupported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
|
||||
{
|
||||
AcpiGedState *s = ACPI_GED(adev);
|
||||
GEDState *ged_st = &s->ged_state;
|
||||
uint32_t sel;
|
||||
|
||||
if (ev & ACPI_MEMORY_HOTPLUG_STATUS) {
|
||||
sel = ACPI_GED_MEM_HOTPLUG_EVT;
|
||||
} else if (ev & ACPI_POWER_DOWN_STATUS) {
|
||||
sel = ACPI_GED_PWR_DOWN_EVT;
|
||||
} else {
|
||||
/* Unknown event. Return without generating interrupt. */
|
||||
warn_report("GED: Unsupported event %d. No irq injected", ev);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the GED selector field to communicate the event type.
|
||||
* This will be read by GED aml code to select the appropriate
|
||||
* event method.
|
||||
*/
|
||||
ged_st->sel |= sel;
|
||||
|
||||
/* Trigger the event by sending an interrupt to the guest. */
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
|
||||
static Property acpi_ged_properties[] = {
|
||||
DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_memhp_state = {
|
||||
.name = "acpi-ged/memhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_ged_state = {
|
||||
.name = "acpi-ged-state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(sel, GEDState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_acpi_ged = {
|
||||
.name = "acpi-ged",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
.subsections = (const VMStateDescription * []) {
|
||||
&vmstate_memhp_state,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static void acpi_ged_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
AcpiGedState *s = ACPI_GED(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
GEDState *ged_st = &s->ged_state;
|
||||
|
||||
memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
|
||||
TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
|
||||
sysbus_init_mmio(sbd, &ged_st->io);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
s->memhp_state.is_enabled = true;
|
||||
/*
|
||||
* GED handles memory hotplug event and acpi-mem-hotplug
|
||||
* memory region gets initialized here. Create an exclusive
|
||||
* container for memory hotplug IO and expose it as GED sysbus
|
||||
* MMIO so that boards can map it separately.
|
||||
*/
|
||||
memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
|
||||
MEMORY_HOTPLUG_IO_LEN);
|
||||
sysbus_init_mmio(sbd, &s->container_memhp);
|
||||
acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
|
||||
&s->memhp_state, 0);
|
||||
}
|
||||
|
||||
static void acpi_ged_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(class);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
|
||||
|
||||
dc->desc = "ACPI Generic Event Device";
|
||||
dc->props = acpi_ged_properties;
|
||||
dc->vmsd = &vmstate_acpi_ged;
|
||||
|
||||
hc->plug = acpi_ged_device_plug_cb;
|
||||
|
||||
adevc->send_event = acpi_ged_send_event;
|
||||
}
|
||||
|
||||
static const TypeInfo acpi_ged_info = {
|
||||
.name = TYPE_ACPI_GED,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AcpiGedState),
|
||||
.instance_init = acpi_ged_initfn,
|
||||
.class_init = acpi_ged_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ TYPE_ACPI_DEVICE_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void acpi_ged_register_types(void)
|
||||
{
|
||||
type_register_static(&acpi_ged_info);
|
||||
}
|
||||
|
||||
type_init(acpi_ged_register_types)
|
|
@ -30,12 +30,7 @@
|
|||
#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
|
||||
#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
|
||||
#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
|
||||
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
|
||||
#define MEMORY_HOTPLUG_DEVICE "MHPD"
|
||||
#define MEMORY_HOTPLUG_IO_LEN 24
|
||||
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
|
||||
|
||||
static uint16_t memhp_io_base;
|
||||
|
||||
static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
|
||||
{
|
||||
|
@ -210,7 +205,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = {
|
|||
};
|
||||
|
||||
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
MemHotplugState *state, uint16_t io_base)
|
||||
MemHotplugState *state, hwaddr io_base)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
|
@ -219,12 +214,10 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
|||
return;
|
||||
}
|
||||
|
||||
assert(!memhp_io_base);
|
||||
memhp_io_base = io_base;
|
||||
state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
|
||||
memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
|
||||
"acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
|
||||
memory_region_add_subregion(as, memhp_io_base, &state->io);
|
||||
memory_region_add_subregion(as, io_base, &state->io);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,7 +336,8 @@ const VMStateDescription vmstate_memory_hotplug = {
|
|||
|
||||
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
const char *res_root,
|
||||
const char *event_handler_method)
|
||||
const char *event_handler_method,
|
||||
AmlRegionSpace rs, hwaddr memhp_io_base)
|
||||
{
|
||||
int i;
|
||||
Aml *ifctx;
|
||||
|
@ -352,10 +346,6 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
|||
Aml *mem_ctrl_dev;
|
||||
char *mhp_res_path;
|
||||
|
||||
if (!memhp_io_base) {
|
||||
return;
|
||||
}
|
||||
|
||||
mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
|
||||
mem_ctrl_dev = aml_device("%s", mhp_res_path);
|
||||
{
|
||||
|
@ -366,14 +356,19 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
|||
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
|
||||
MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
if (rs == AML_SYSTEM_IO) {
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
|
||||
MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
} else {
|
||||
aml_append(crs, aml_memory32_fixed(memhp_io_base,
|
||||
MEMORY_HOTPLUG_IO_LEN, AML_READ_WRITE));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_operation_region(
|
||||
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
|
||||
MEMORY_HOTPLUG_IO_REGION, rs,
|
||||
aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
|
||||
|
@ -717,10 +712,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
|||
}
|
||||
aml_append(table, dev_container);
|
||||
|
||||
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
|
||||
aml_append(method,
|
||||
aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD));
|
||||
aml_append(table, method);
|
||||
if (event_handler_method) {
|
||||
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_call0(MEMORY_DEVICES_CONTAINER "."
|
||||
MEMORY_SLOT_SCAN_METHOD));
|
||||
aml_append(table, method);
|
||||
}
|
||||
|
||||
g_free(mhp_res_path);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ config ARM_VIRT
|
|||
select SMBIOS
|
||||
select VIRTIO_MMIO
|
||||
select ACPI_PCI
|
||||
select MEM_DEVICE
|
||||
select DIMM
|
||||
select ACPI_MEMORY_HOTPLUG
|
||||
select ACPI_HW_REDUCED
|
||||
|
||||
config CHEETAH
|
||||
bool
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/acpi/pci.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/arm/virt.h"
|
||||
|
@ -48,7 +50,6 @@
|
|||
#include "migration/vmstate.h"
|
||||
|
||||
#define ARM_SPI_BASE 32
|
||||
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
||||
|
||||
static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
|
||||
{
|
||||
|
@ -544,6 +545,14 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
|||
}
|
||||
}
|
||||
|
||||
if (ms->device_memory) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
build_srat_memory(numamem, ms->device_memory->base,
|
||||
memory_region_size(&ms->device_memory->mr),
|
||||
ms->numa_state->num_nodes - 1,
|
||||
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
|
||||
build_header(linker, table_data, (void *)(table_data->data + srat_start),
|
||||
"SRAT", table_data->len - srat_start, 3, NULL, NULL);
|
||||
}
|
||||
|
@ -708,6 +717,7 @@ static void
|
|||
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
Aml *scope, *dsdt;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
const int *irqmap = vms->irqmap;
|
||||
|
||||
|
@ -730,8 +740,27 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
|||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
|
||||
vms->highmem, vms->highmem_ecam);
|
||||
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
|
||||
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
|
||||
if (vms->acpi_dev) {
|
||||
build_ged_aml(scope, "\\_SB."GED_DEVICE,
|
||||
HOTPLUG_HANDLER(vms->acpi_dev),
|
||||
irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY,
|
||||
memmap[VIRT_ACPI_GED].base);
|
||||
} else {
|
||||
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
|
||||
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
|
||||
}
|
||||
|
||||
if (vms->acpi_dev) {
|
||||
uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev),
|
||||
"ged-event", &error_abort);
|
||||
|
||||
if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
|
||||
build_memory_hotplug_aml(scope, ms->ram_slots, "\\_SB", NULL,
|
||||
AML_SYSTEM_MEMORY,
|
||||
memmap[VIRT_PCDIMM_ACPI].base);
|
||||
}
|
||||
}
|
||||
|
||||
acpi_dsdt_add_power_button(scope);
|
||||
|
||||
aml_append(dsdt, scope);
|
||||
|
|
124
hw/arm/virt.c
124
hw/arm/virt.c
|
@ -68,6 +68,9 @@
|
|||
#include "hw/arm/smmuv3.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "target/arm/internals.h"
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "hw/mem/nvdimm.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
|
||||
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
|
||||
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
|
||||
|
@ -138,6 +141,8 @@ static const MemMapEntry base_memmap[] = {
|
|||
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
|
||||
[VIRT_SECURE_UART] = { 0x09040000, 0x00001000 },
|
||||
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
|
||||
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
|
||||
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
|
||||
|
@ -173,6 +178,7 @@ static const int a15irqmap[] = {
|
|||
[VIRT_PCIE] = 3, /* ... to 6 */
|
||||
[VIRT_GPIO] = 7,
|
||||
[VIRT_SECURE_UART] = 8,
|
||||
[VIRT_ACPI_GED] = 9,
|
||||
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
|
||||
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
|
||||
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
|
||||
|
@ -525,6 +531,29 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
|
|||
}
|
||||
}
|
||||
|
||||
static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
|
||||
{
|
||||
DeviceState *dev;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
int irq = vms->irqmap[VIRT_ACPI_GED];
|
||||
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
|
||||
|
||||
if (ms->ram_slots) {
|
||||
event |= ACPI_GED_MEM_HOTPLUG_EVT;
|
||||
}
|
||||
|
||||
dev = qdev_create(NULL, TYPE_ACPI_GED);
|
||||
qdev_prop_set_uint32(dev, "ged-event", event);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void create_its(VirtMachineState *vms, DeviceState *gicdev)
|
||||
{
|
||||
const char *itsclass = its_class_name();
|
||||
|
@ -764,13 +793,15 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
|
|||
static DeviceState *gpio_key_dev;
|
||||
static void virt_powerdown_req(Notifier *n, void *opaque)
|
||||
{
|
||||
/* use gpio Pin 3 for power button event */
|
||||
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
|
||||
}
|
||||
VirtMachineState *s = container_of(n, VirtMachineState, powerdown_notifier);
|
||||
|
||||
static Notifier virt_system_powerdown_notifier = {
|
||||
.notify = virt_powerdown_req
|
||||
};
|
||||
if (s->acpi_dev) {
|
||||
acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS);
|
||||
} else {
|
||||
/* use gpio Pin 3 for power button event */
|
||||
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
|
||||
{
|
||||
|
@ -812,10 +843,6 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
|
|||
KEY_POWER);
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff",
|
||||
"gpios", phandle, 3, 0);
|
||||
|
||||
/* connect powerdown request */
|
||||
qemu_register_powerdown_notifier(&virt_system_powerdown_notifier);
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
|
@ -1489,6 +1516,7 @@ static void machvirt_init(MachineState *machine)
|
|||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
bool firmware_loaded;
|
||||
bool aarch64 = true;
|
||||
bool has_ged = !vmc->no_ged;
|
||||
unsigned int smp_cpus = machine->smp.cpus;
|
||||
unsigned int max_cpus = machine->smp.max_cpus;
|
||||
|
||||
|
@ -1701,7 +1729,15 @@ static void machvirt_init(MachineState *machine)
|
|||
|
||||
create_pcie(vms, pic);
|
||||
|
||||
create_gpio(vms, pic);
|
||||
if (has_ged && aarch64 && firmware_loaded && acpi_enabled) {
|
||||
vms->acpi_dev = create_acpi_ged(vms, pic);
|
||||
} else {
|
||||
create_gpio(vms, pic);
|
||||
}
|
||||
|
||||
/* connect powerdown request */
|
||||
vms->powerdown_notifier.notify = virt_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&vms->powerdown_notifier);
|
||||
|
||||
/* Create mmio transports, so the user can create virtio backends
|
||||
* (which will be automatically plugged in to the transports). If
|
||||
|
@ -1876,6 +1912,52 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
|
|||
return ms->possible_cpus;
|
||||
}
|
||||
|
||||
static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||||
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
||||
|
||||
if (is_nvdimm) {
|
||||
error_setg(errp, "nvdimm is not yet supported");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vms->acpi_dev) {
|
||||
error_setg(errp,
|
||||
"memory hotplug is not enabled: missing acpi-ged device");
|
||||
return;
|
||||
}
|
||||
|
||||
pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp);
|
||||
}
|
||||
|
||||
static void virt_memory_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
HotplugHandlerClass *hhc;
|
||||
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev);
|
||||
hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
virt_memory_pre_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
|
@ -1887,12 +1969,23 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||
SYS_BUS_DEVICE(dev));
|
||||
}
|
||||
}
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
virt_memory_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "device unplug request for unsupported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
|
||||
static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) {
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) ||
|
||||
(object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
|
||||
|
@ -1956,8 +2049,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->kvm_type = virt_kvm_type;
|
||||
assert(!mc->get_hotplug_handler);
|
||||
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
|
||||
hc->pre_plug = virt_machine_device_pre_plug_cb;
|
||||
hc->plug = virt_machine_device_plug_cb;
|
||||
hc->unplug_request = virt_machine_device_unplug_request_cb;
|
||||
mc->numa_mem_supported = true;
|
||||
mc->auto_enable_numa_with_memhp = true;
|
||||
}
|
||||
|
||||
static void virt_instance_init(Object *obj)
|
||||
|
@ -2058,8 +2154,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(4, 2)
|
|||
|
||||
static void virt_machine_4_1_options(MachineClass *mc)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
|
||||
|
||||
virt_machine_4_2_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
|
||||
vmc->no_ged = true;
|
||||
mc->auto_enable_numa_with_memhp = false;
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(4, 1)
|
||||
|
||||
|
|
|
@ -1888,7 +1888,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
|
||||
"\\_SB.PCI0", "\\_GPE._E02");
|
||||
}
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03");
|
||||
|
||||
if (pcms->memhp_io_base && nr_mem) {
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0",
|
||||
"\\_GPE._E03", AML_SYSTEM_IO,
|
||||
pcms->memhp_io_base);
|
||||
}
|
||||
|
||||
scope = aml_scope("_GPE");
|
||||
{
|
||||
|
|
|
@ -1766,6 +1766,9 @@ void pc_memory_init(PCMachineState *pcms,
|
|||
|
||||
/* Init default IOAPIC address space */
|
||||
pcms->ioapic_as = &address_space_memory;
|
||||
|
||||
/* Init ACPI memory hotplug IO base address */
|
||||
pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,9 +11,11 @@ common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
|
|||
common-obj-$(CONFIG_VIRTIO_MMIO) += virtio-mmio.o
|
||||
obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
|
||||
obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
|
||||
obj-$(CONFIG_VHOST_USER_FS) += vhost-user-fs.o
|
||||
obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
|
||||
obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
|
||||
common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
|
||||
obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o
|
||||
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO_PCI),y)
|
||||
|
|
85
hw/virtio/vhost-user-fs-pci.c
Normal file
85
hw/virtio/vhost-user-fs-pci.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Vhost-user filesystem virtio device PCI glue
|
||||
*
|
||||
* Copyright 2018-2019 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/virtio/vhost-user-fs.h"
|
||||
#include "virtio-pci.h"
|
||||
|
||||
struct VHostUserFSPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VHostUserFS vdev;
|
||||
};
|
||||
|
||||
typedef struct VHostUserFSPCI VHostUserFSPCI;
|
||||
|
||||
#define TYPE_VHOST_USER_FS_PCI "vhost-user-fs-pci-base"
|
||||
|
||||
#define VHOST_USER_FS_PCI(obj) \
|
||||
OBJECT_CHECK(VHostUserFSPCI, (obj), TYPE_VHOST_USER_FS_PCI)
|
||||
|
||||
static Property vhost_user_fs_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VHostUserFSPCI *dev = VHOST_USER_FS_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = dev->vdev.conf.num_request_queues + 1;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void vhost_user_fs_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = vhost_user_fs_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = vhost_user_fs_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
|
||||
pcidev_k->revision = 0x00;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_OTHER;
|
||||
}
|
||||
|
||||
static void vhost_user_fs_pci_instance_init(Object *obj)
|
||||
{
|
||||
VHostUserFSPCI *dev = VHOST_USER_FS_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_USER_FS);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo vhost_user_fs_pci_info = {
|
||||
.base_name = TYPE_VHOST_USER_FS_PCI,
|
||||
.non_transitional_name = "vhost-user-fs-pci",
|
||||
.instance_size = sizeof(VHostUserFSPCI),
|
||||
.instance_init = vhost_user_fs_pci_instance_init,
|
||||
.class_init = vhost_user_fs_pci_class_init,
|
||||
};
|
||||
|
||||
static void vhost_user_fs_pci_register(void)
|
||||
{
|
||||
virtio_pci_types_register(&vhost_user_fs_pci_info);
|
||||
}
|
||||
|
||||
type_init(vhost_user_fs_pci_register);
|
299
hw/virtio/vhost-user-fs.c
Normal file
299
hw/virtio/vhost-user-fs.c
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* Vhost-user filesystem virtio device
|
||||
*
|
||||
* Copyright 2018-2019 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Hajnoczi <stefanha@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include "standard-headers/linux/virtio_fs.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/virtio/vhost-user-fs.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
static void vuf_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
struct virtio_fs_config fscfg = {};
|
||||
|
||||
memcpy((char *)fscfg.tag, fs->conf.tag,
|
||||
MIN(strlen(fs->conf.tag) + 1, sizeof(fscfg.tag)));
|
||||
|
||||
virtio_stl_p(vdev, &fscfg.num_request_queues, fs->conf.num_request_queues);
|
||||
|
||||
memcpy(config, &fscfg, sizeof(fscfg));
|
||||
}
|
||||
|
||||
static void vuf_start(VirtIODevice *vdev)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vhost_dev_enable_notifiers(&fs->vhost_dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error enabling host notifiers: %d", -ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, true);
|
||||
if (ret < 0) {
|
||||
error_report("Error binding guest notifier: %d", -ret);
|
||||
goto err_host_notifiers;
|
||||
}
|
||||
|
||||
fs->vhost_dev.acked_features = vdev->guest_features;
|
||||
ret = vhost_dev_start(&fs->vhost_dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error starting vhost: %d", -ret);
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_notifier_mask/pending not used yet, so just unmask
|
||||
* everything here. virtio-pci will do the right thing by
|
||||
* enabling/disabling irqfd.
|
||||
*/
|
||||
for (i = 0; i < fs->vhost_dev.nvqs; i++) {
|
||||
vhost_virtqueue_mask(&fs->vhost_dev, vdev, i, false);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_guest_notifiers:
|
||||
k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
|
||||
err_host_notifiers:
|
||||
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
|
||||
}
|
||||
|
||||
static void vuf_stop(VirtIODevice *vdev)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int ret;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
vhost_dev_stop(&fs->vhost_dev, vdev);
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
|
||||
if (ret < 0) {
|
||||
error_report("vhost guest notifier cleanup failed: %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
|
||||
}
|
||||
|
||||
static void vuf_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
|
||||
|
||||
if (!vdev->vm_running) {
|
||||
should_start = false;
|
||||
}
|
||||
|
||||
if (fs->vhost_dev.started == should_start) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_start) {
|
||||
vuf_start(vdev);
|
||||
} else {
|
||||
vuf_stop(vdev);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t vuf_get_features(VirtIODevice *vdev,
|
||||
uint64_t requested_features,
|
||||
Error **errp)
|
||||
{
|
||||
/* No feature bits used yet */
|
||||
return requested_features;
|
||||
}
|
||||
|
||||
static void vuf_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
/*
|
||||
* Not normally called; it's the daemon that handles the queue;
|
||||
* however virtio's cleanup path can call this.
|
||||
*/
|
||||
}
|
||||
|
||||
static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx,
|
||||
bool mask)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
|
||||
vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask);
|
||||
}
|
||||
|
||||
static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx)
|
||||
{
|
||||
VHostUserFS *fs = VHOST_USER_FS(vdev);
|
||||
|
||||
return vhost_virtqueue_pending(&fs->vhost_dev, idx);
|
||||
}
|
||||
|
||||
static void vuf_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserFS *fs = VHOST_USER_FS(dev);
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (!fs->conf.chardev.chr) {
|
||||
error_setg(errp, "missing chardev");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs->conf.tag) {
|
||||
error_setg(errp, "missing tag property");
|
||||
return;
|
||||
}
|
||||
len = strlen(fs->conf.tag);
|
||||
if (len == 0) {
|
||||
error_setg(errp, "tag property cannot be empty");
|
||||
return;
|
||||
}
|
||||
if (len > sizeof_field(struct virtio_fs_config, tag)) {
|
||||
error_setg(errp, "tag property must be %zu bytes or less",
|
||||
sizeof_field(struct virtio_fs_config, tag));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs->conf.num_request_queues == 0) {
|
||||
error_setg(errp, "num-request-queues property must be larger than 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_power_of_2(fs->conf.queue_size)) {
|
||||
error_setg(errp, "queue-size property must be a power of 2");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs->conf.queue_size > VIRTQUEUE_MAX_SIZE) {
|
||||
error_setg(errp, "queue-size property must be %u or smaller",
|
||||
VIRTQUEUE_MAX_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vhost_user_init(&fs->vhost_user, &fs->conf.chardev, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS,
|
||||
sizeof(struct virtio_fs_config));
|
||||
|
||||
/* Hiprio queue */
|
||||
virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
|
||||
|
||||
/* Request queues */
|
||||
for (i = 0; i < fs->conf.num_request_queues; i++) {
|
||||
virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
|
||||
}
|
||||
|
||||
/* 1 high prio queue, plus the number configured */
|
||||
fs->vhost_dev.nvqs = 1 + fs->conf.num_request_queues;
|
||||
fs->vhost_dev.vqs = g_new0(struct vhost_virtqueue, fs->vhost_dev.nvqs);
|
||||
ret = vhost_dev_init(&fs->vhost_dev, &fs->vhost_user,
|
||||
VHOST_BACKEND_TYPE_USER, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "vhost_dev_init failed");
|
||||
goto err_virtio;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_virtio:
|
||||
vhost_user_cleanup(&fs->vhost_user);
|
||||
virtio_cleanup(vdev);
|
||||
g_free(fs->vhost_dev.vqs);
|
||||
return;
|
||||
}
|
||||
|
||||
static void vuf_device_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserFS *fs = VHOST_USER_FS(dev);
|
||||
|
||||
/* This will stop vhost backend if appropriate. */
|
||||
vuf_set_status(vdev, 0);
|
||||
|
||||
vhost_dev_cleanup(&fs->vhost_dev);
|
||||
|
||||
vhost_user_cleanup(&fs->vhost_user);
|
||||
|
||||
virtio_cleanup(vdev);
|
||||
g_free(fs->vhost_dev.vqs);
|
||||
fs->vhost_dev.vqs = NULL;
|
||||
}
|
||||
|
||||
static const VMStateDescription vuf_vmstate = {
|
||||
.name = "vhost-user-fs",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static Property vuf_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", VHostUserFS, conf.chardev),
|
||||
DEFINE_PROP_STRING("tag", VHostUserFS, conf.tag),
|
||||
DEFINE_PROP_UINT16("num-request-queues", VHostUserFS,
|
||||
conf.num_request_queues, 1),
|
||||
DEFINE_PROP_UINT16("queue-size", VHostUserFS, conf.queue_size, 128),
|
||||
DEFINE_PROP_STRING("vhostfd", VHostUserFS, conf.vhostfd),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vuf_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = vuf_properties;
|
||||
dc->vmsd = &vuf_vmstate;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->realize = vuf_device_realize;
|
||||
vdc->unrealize = vuf_device_unrealize;
|
||||
vdc->get_features = vuf_get_features;
|
||||
vdc->get_config = vuf_get_config;
|
||||
vdc->set_status = vuf_set_status;
|
||||
vdc->guest_notifier_mask = vuf_guest_notifier_mask;
|
||||
vdc->guest_notifier_pending = vuf_guest_notifier_pending;
|
||||
}
|
||||
|
||||
static const TypeInfo vuf_info = {
|
||||
.name = TYPE_VHOST_USER_FS,
|
||||
.parent = TYPE_VIRTIO_DEVICE,
|
||||
.instance_size = sizeof(VHostUserFS),
|
||||
.class_init = vuf_class_init,
|
||||
};
|
||||
|
||||
static void vuf_register_types(void)
|
||||
{
|
||||
type_register_static(&vuf_info);
|
||||
}
|
||||
|
||||
type_init(vuf_register_types)
|
|
@ -13,6 +13,7 @@ typedef enum {
|
|||
ACPI_MEMORY_HOTPLUG_STATUS = 8,
|
||||
ACPI_NVDIMM_HOTPLUG_STATUS = 16,
|
||||
ACPI_VMGENID_CHANGE_STATUS = 32,
|
||||
ACPI_POWER_DOWN_STATUS = 64,
|
||||
} AcpiEventStatusBits;
|
||||
|
||||
#define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
|
||||
|
|
103
include/hw/acpi/generic_event_device.h
Normal file
103
include/hw/acpi/generic_event_device.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
|
||||
* Written by Samuel Ortiz, Shameer Kolothum
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* The ACPI Generic Event Device (GED) is a hardware-reduced specific
|
||||
* device[ACPI v6.1 Section 5.6.9] that handles all platform events,
|
||||
* including the hotplug ones. Generic Event Device allows platforms
|
||||
* to handle interrupts in ACPI ASL statements. It follows a very
|
||||
* similar approach like the _EVT method from GPIO events. All
|
||||
* interrupts are listed in _CRS and the handler is written in _EVT
|
||||
* method. Here, we use a single interrupt for the GED device, relying
|
||||
* on IO memory region to communicate the type of device affected by
|
||||
* the interrupt. This way, we can support up to 32 events with a
|
||||
* unique interrupt.
|
||||
*
|
||||
* Here is an example.
|
||||
*
|
||||
* Device (\_SB.GED)
|
||||
* {
|
||||
* Name (_HID, "ACPI0013")
|
||||
* Name (_UID, Zero)
|
||||
* Name (_CRS, ResourceTemplate ()
|
||||
* {
|
||||
* Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
|
||||
* {
|
||||
* 0x00000029,
|
||||
* }
|
||||
* })
|
||||
* OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
|
||||
* Field (EREG, DWordAcc, NoLock, WriteAsZeros)
|
||||
* {
|
||||
* ESEL, 32
|
||||
* }
|
||||
*
|
||||
* Method (_EVT, 1, Serialized) // _EVT: Event
|
||||
* {
|
||||
* Local0 = ESEL // ESEL = IO memory region which specifies the
|
||||
* // device type.
|
||||
* If (((Local0 & One) == One))
|
||||
* {
|
||||
* MethodEvent1()
|
||||
* }
|
||||
* If ((Local0 & 0x2) == 0x2)
|
||||
* {
|
||||
* MethodEvent2()
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HW_ACPI_GED_H
|
||||
#define HW_ACPI_GED_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
|
||||
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
||||
|
||||
#define TYPE_ACPI_GED "acpi-ged"
|
||||
#define ACPI_GED(obj) \
|
||||
OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED)
|
||||
|
||||
#define ACPI_GED_EVT_SEL_OFFSET 0x0
|
||||
#define ACPI_GED_EVT_SEL_LEN 0x4
|
||||
|
||||
#define GED_DEVICE "GED"
|
||||
#define AML_GED_EVT_REG "EREG"
|
||||
#define AML_GED_EVT_SEL "ESEL"
|
||||
|
||||
/*
|
||||
* Platforms need to specify the GED event bitmap
|
||||
* to describe what kind of events they want to support
|
||||
* through GED.
|
||||
*/
|
||||
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
|
||||
#define ACPI_GED_PWR_DOWN_EVT 0x2
|
||||
|
||||
typedef struct GEDState {
|
||||
MemoryRegion io;
|
||||
uint32_t sel;
|
||||
} GEDState;
|
||||
|
||||
typedef struct AcpiGedState {
|
||||
SysBusDevice parent_obj;
|
||||
MemHotplugState memhp_state;
|
||||
MemoryRegion container_memhp;
|
||||
GEDState ged_state;
|
||||
uint32_t ged_event_bitmap;
|
||||
qemu_irq irq;
|
||||
} AcpiGedState;
|
||||
|
||||
void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
|
||||
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
|
||||
|
||||
#endif
|
|
@ -5,6 +5,10 @@
|
|||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
|
||||
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
|
||||
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
|
||||
#define MEMORY_HOTPLUG_IO_LEN 24
|
||||
|
||||
/**
|
||||
* MemStatus:
|
||||
* @is_removing: the memory device in slot has been requested to be ejected.
|
||||
|
@ -29,7 +33,7 @@ typedef struct MemHotplugState {
|
|||
} MemHotplugState;
|
||||
|
||||
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
MemHotplugState *state, uint16_t io_base);
|
||||
MemHotplugState *state, hwaddr io_base);
|
||||
|
||||
void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp);
|
||||
|
@ -48,5 +52,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list);
|
|||
|
||||
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
const char *res_root,
|
||||
const char *event_handler_method);
|
||||
const char *event_handler_method,
|
||||
AmlRegionSpace rs, hwaddr memhp_io_base);
|
||||
#endif
|
||||
|
|
|
@ -77,6 +77,8 @@ enum {
|
|||
VIRT_GPIO,
|
||||
VIRT_SECURE_UART,
|
||||
VIRT_SECURE_MEM,
|
||||
VIRT_PCDIMM_ACPI,
|
||||
VIRT_ACPI_GED,
|
||||
VIRT_LOWMEMMAP_LAST,
|
||||
};
|
||||
|
||||
|
@ -106,6 +108,7 @@ typedef struct {
|
|||
bool claim_edge_triggered_timers;
|
||||
bool smbios_old_sys_ver;
|
||||
bool no_highmem_ecam;
|
||||
bool no_ged; /* Machines < 4.2 has no support for ACPI GED device */
|
||||
} VirtMachineClass;
|
||||
|
||||
typedef struct {
|
||||
|
@ -133,6 +136,8 @@ typedef struct {
|
|||
uint32_t iommu_phandle;
|
||||
int psci_conduit;
|
||||
hwaddr highest_gpa;
|
||||
DeviceState *acpi_dev;
|
||||
Notifier powerdown_notifier;
|
||||
} VirtMachineState;
|
||||
|
||||
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
|
||||
|
|
|
@ -70,6 +70,9 @@ struct PCMachineState {
|
|||
/* Address space used by IOAPIC device. All IOAPIC interrupts
|
||||
* will be translated to MSI messages in the address space. */
|
||||
AddressSpace *ioapic_as;
|
||||
|
||||
/* ACPI Memory hotplug IO base address */
|
||||
hwaddr memhp_io_base;
|
||||
};
|
||||
|
||||
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
|
||||
|
|
45
include/hw/virtio/vhost-user-fs.h
Normal file
45
include/hw/virtio/vhost-user-fs.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Vhost-user filesystem virtio device
|
||||
*
|
||||
* Copyright 2018-2019 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Hajnoczi <stefanha@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef _QEMU_VHOST_USER_FS_H
|
||||
#define _QEMU_VHOST_USER_FS_H
|
||||
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/vhost-user.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
#define TYPE_VHOST_USER_FS "vhost-user-fs-device"
|
||||
#define VHOST_USER_FS(obj) \
|
||||
OBJECT_CHECK(VHostUserFS, (obj), TYPE_VHOST_USER_FS)
|
||||
|
||||
typedef struct {
|
||||
CharBackend chardev;
|
||||
char *tag;
|
||||
uint16_t num_request_queues;
|
||||
uint16_t queue_size;
|
||||
char *vhostfd;
|
||||
} VHostUserFSConf;
|
||||
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
VirtIODevice parent;
|
||||
VHostUserFSConf conf;
|
||||
struct vhost_virtqueue *vhost_vqs;
|
||||
struct vhost_dev vhost_dev;
|
||||
VhostUserState vhost_user;
|
||||
|
||||
/*< public >*/
|
||||
} VHostUserFS;
|
||||
|
||||
#endif /* _QEMU_VHOST_USER_FS_H */
|
|
@ -235,6 +235,10 @@ static void chr_closed_bh(void *opaque)
|
|||
|
||||
s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
|
||||
|
||||
if (s->vhost_net) {
|
||||
s->acked_features = vhost_net_get_acked_features(s->vhost_net);
|
||||
}
|
||||
|
||||
qmp_set_link(name, false, &err);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
|
||||
|
|
|
@ -10,6 +10,33 @@
|
|||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* How to add or update the tests:
|
||||
* Contributor:
|
||||
* 1. add empty files for new tables, if any, under tests/data/acpi
|
||||
* 2. list any changed files in tests/bios-tables-test-allowed-diff.h
|
||||
* 3. commit the above *before* making changes that affect the tables
|
||||
* Maintainer:
|
||||
* After 1-3 above tests will pass but ignore differences with the expected files.
|
||||
* You will also notice that tests/bios-tables-test-allowed-diff.h lists
|
||||
* a bunch of files. This is your hint that you need to do the below:
|
||||
* 4. Run
|
||||
* make check V=1
|
||||
* this will produce a bunch of warnings about differences
|
||||
* beween actual and expected ACPI tables. If you have IASL installed,
|
||||
* they will also be disassembled so you can look at the disassembled
|
||||
* output. If not - disassemble them yourself in any way you like.
|
||||
* Look at the differences - make sure they make sense and match what the
|
||||
* changes you are merging are supposed to do.
|
||||
*
|
||||
* 5. From build directory, run:
|
||||
* $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
|
||||
* 6. Now commit any changes.
|
||||
* 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h
|
||||
* is empty - this will ensure following changes to ACPI tables will
|
||||
* be noticed.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <glib/gstdio.h>
|
||||
#include "qemu-common.h"
|
||||
|
@ -334,7 +361,10 @@ try_again:
|
|||
g_assert(ret);
|
||||
g_assert_no_error(error);
|
||||
g_assert(exp_sdt.aml);
|
||||
g_assert(exp_sdt.aml_len);
|
||||
if (!exp_sdt.aml_len) {
|
||||
fprintf(stderr, "Warning! zero length expected file '%s'\n",
|
||||
aml_file);
|
||||
}
|
||||
|
||||
g_array_append_val(exp_tables, exp_sdt);
|
||||
}
|
||||
|
@ -870,6 +900,53 @@ static void test_acpi_piix4_tcg_dimm_pxm(void)
|
|||
test_acpi_tcg_dimm_pxm(MACHINE_PC);
|
||||
}
|
||||
|
||||
static void test_acpi_virt_tcg_memhp(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = "virt",
|
||||
.accel = "tcg",
|
||||
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
|
||||
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
|
||||
.cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
|
||||
.ram_start = 0x40000000ULL,
|
||||
.scan_len = 256ULL * 1024 * 1024,
|
||||
};
|
||||
|
||||
data.variant = ".memhp";
|
||||
test_acpi_one(" -cpu cortex-a57"
|
||||
" -m 256M,slots=3,maxmem=1G"
|
||||
" -object memory-backend-ram,id=ram0,size=128M"
|
||||
" -object memory-backend-ram,id=ram1,size=128M"
|
||||
" -numa node,memdev=ram0 -numa node,memdev=ram1"
|
||||
" -numa dist,src=0,dst=1,val=21",
|
||||
&data);
|
||||
|
||||
free_test_data(&data);
|
||||
|
||||
}
|
||||
|
||||
static void test_acpi_virt_tcg_numamem(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = "virt",
|
||||
.accel = "tcg",
|
||||
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
|
||||
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
|
||||
.cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
|
||||
.ram_start = 0x40000000ULL,
|
||||
.scan_len = 128ULL * 1024 * 1024,
|
||||
};
|
||||
|
||||
data.variant = ".numamem";
|
||||
test_acpi_one(" -cpu cortex-a57"
|
||||
" -object memory-backend-ram,id=ram0,size=128M"
|
||||
" -numa node,memdev=ram0",
|
||||
&data);
|
||||
|
||||
free_test_data(&data);
|
||||
|
||||
}
|
||||
|
||||
static void test_acpi_virt_tcg(void)
|
||||
{
|
||||
test_data data = {
|
||||
|
@ -916,6 +993,8 @@ int main(int argc, char *argv[])
|
|||
qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
|
||||
} else if (strcmp(arch, "aarch64") == 0) {
|
||||
qtest_add_func("acpi/virt", test_acpi_virt_tcg);
|
||||
qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
|
||||
qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
|
||||
}
|
||||
ret = g_test_run();
|
||||
boot_sector_cleanup(disk);
|
||||
|
|
BIN
tests/data/acpi/virt/APIC.memhp
Normal file
BIN
tests/data/acpi/virt/APIC.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/APIC.numamem
Normal file
BIN
tests/data/acpi/virt/APIC.numamem
Normal file
Binary file not shown.
Binary file not shown.
BIN
tests/data/acpi/virt/DSDT.memhp
Normal file
BIN
tests/data/acpi/virt/DSDT.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/DSDT.numamem
Normal file
BIN
tests/data/acpi/virt/DSDT.numamem
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/FACP.memhp
Normal file
BIN
tests/data/acpi/virt/FACP.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/FACP.numamem
Normal file
BIN
tests/data/acpi/virt/FACP.numamem
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/GTDT.memhp
Normal file
BIN
tests/data/acpi/virt/GTDT.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/GTDT.numamem
Normal file
BIN
tests/data/acpi/virt/GTDT.numamem
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/MCFG.memhp
Normal file
BIN
tests/data/acpi/virt/MCFG.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/MCFG.numamem
Normal file
BIN
tests/data/acpi/virt/MCFG.numamem
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/SLIT.memhp
Normal file
BIN
tests/data/acpi/virt/SLIT.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/SPCR.memhp
Normal file
BIN
tests/data/acpi/virt/SPCR.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/SPCR.numamem
Normal file
BIN
tests/data/acpi/virt/SPCR.numamem
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/SRAT.memhp
Normal file
BIN
tests/data/acpi/virt/SRAT.memhp
Normal file
Binary file not shown.
BIN
tests/data/acpi/virt/SRAT.numamem
Normal file
BIN
tests/data/acpi/virt/SRAT.numamem
Normal file
Binary file not shown.
Loading…
Reference in a new issue