mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-01 09:42:58 +00:00
pc, virtio enhancements
Memory hot-unplug support for pc, MSI-X mapping update speedup for virtio-pci, misc refactorings and bugfixes. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVUFj/AAoJECgfDbjSjVRpteQH+gKoOMKilM6qvgdQS9vduFJ+ lDHNnmfgzWjVMEetiUOc9hImfEEyTyDFrkSI3wf4a8RZ7UnnDKD8hZR1nToySJPd SuDP/EdtXYtInIMjc1MUUrJEP6qtjjgM+IbikVzHDxCeekrTMFz2w05MZ+V+hxI5 8b8ndPNfjX3ciIRjHKZ2u6hKEemhzxr1yyKTnJVGDN07hmfMbCyLsiWnFfShZwfv g7USgiXjFfpvU5Q7QWpiCapfAaEpevRqieGzRjSbPy5Frm3XT7v+hWbFnvIJqUPj 5/SMV8I4qtKQe15Qah292HB//oaFM/AvRtHWvQkre3YIqFwyCYimQtjqoRCYC1E= =x0ub -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging pc, virtio enhancements Memory hot-unplug support for pc, MSI-X mapping update speedup for virtio-pci, misc refactorings and bugfixes. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Mon May 11 08:23:43 2015 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: (28 commits) acpi: update expected files for memory unplug virtio-scsi: Move DEFINE_VIRTIO_SCSI_FEATURES to virtio-scsi virtio-net: Move DEFINE_VIRTIO_NET_FEATURES to virtio-net pci: Merge pci_nic_init() into pci_nic_init_nofail() acpi: add a missing backslash to the \_SB scope. qmp-event: add event notification for memory hot unplug error acpi: add hardware implementation for memory hot unplug acpi: fix "Memory device control fields" register acpi: extend aml_field() to support UpdateRule acpi, mem-hotplug: add unplug cb for memory device acpi, mem-hotplug: add unplug request cb for memory device acpi, mem-hotplug: add acpi_memory_slot_status() to get MemStatus docs: update documentation for memory hot unplug virtio: coding style tweak pci: remove hard-coded bar size in msix_init_exclusive_bar() virtio-pci: speedup MSI-X masking and unmasking virtio: introduce vector to virtqueues mapping virtio-ccw: using VIRTIO_NO_VECTOR instead of 0 for invalid virtqueue monitor: check return value of qemu_find_net_clients_except() monitor: replace the magic number 255 with MAX_QUEUE_NUM ... Conflicts: hw/s390x/s390-virtio-bus.c [PMM: fixed conflict in s390_virtio_scsi_properties and s390_virtio_net_properties arrays; since the result of the two conflicting patches is to empty the property arrays completely, the conflict resolution is to remove them entirely.] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0403b0f539
@ -4,9 +4,7 @@ QEMU memory hotplug
|
||||
This document explains how to use the memory hotplug feature in QEMU,
|
||||
which is present since v2.1.0.
|
||||
|
||||
Please, note that memory hotunplug is not supported yet. This means
|
||||
that you're able to add memory, but you're not able to remove it.
|
||||
Also, proper guest support is required for memory hotplug to work.
|
||||
Guest support is required for memory hotplug to work.
|
||||
|
||||
Basic RAM hotplug
|
||||
-----------------
|
||||
@ -74,3 +72,22 @@ comes from regular RAM, 1GB is a 1GB hugepage page and 256MB is from
|
||||
-device pc-dimm,id=dimm1,memdev=mem1 \
|
||||
-object memory-backend-file,id=mem2,size=256M,mem-path=/mnt/hugepages-2MB \
|
||||
-device pc-dimm,id=dimm2,memdev=mem2
|
||||
|
||||
|
||||
RAM hot-unplug
|
||||
---------------
|
||||
|
||||
In order to be able to hot unplug pc-dimm device, QEMU has to be told the ids
|
||||
of pc-dimm device and memory backend object. The ids were assigned when you hot
|
||||
plugged memory.
|
||||
|
||||
Two monitor commands are used to hot unplug memory:
|
||||
|
||||
- "device_del": deletes a front-end pc-dimm device
|
||||
- "object_del": deletes a memory backend object
|
||||
|
||||
For example, assuming that the pc-dimm device with id "dimm1" exists, and its memory
|
||||
backend is "mem1", the following commands tries to remove it.
|
||||
|
||||
(qemu) device_del dimm1
|
||||
(qemu) object_del mem1
|
||||
|
@ -232,6 +232,23 @@ Example:
|
||||
{ "event": "GUEST_PANICKED",
|
||||
"data": { "action": "pause" } }
|
||||
|
||||
MEM_HOT_UNPLUG_ERROR
|
||||
--------------------
|
||||
Emitted when memory hot unplug error occurs.
|
||||
|
||||
Data:
|
||||
|
||||
- "device": device name (json-string)
|
||||
- "msg": Informative message (e.g., reason for the error) (json-string)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "MEM_HOT_UNPLUG_ERROR"
|
||||
"data": { "device": "dimm1",
|
||||
"msg": "acpi: device unplug for unsupported device"
|
||||
},
|
||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
|
||||
NIC_RX_FILTER_CHANGED
|
||||
---------------------
|
||||
|
||||
|
@ -2,7 +2,7 @@ QEMU<->ACPI BIOS memory hotplug interface
|
||||
--------------------------------------
|
||||
|
||||
ACPI BIOS GPE.3 handler is dedicated for notifying OS about memory hot-add
|
||||
events.
|
||||
and hot-remove events.
|
||||
|
||||
Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
|
||||
---------------------------------------------------------------
|
||||
@ -19,7 +19,9 @@ Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
|
||||
1: Device insert event, used to distinguish device for which
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 1 is set.
|
||||
2-7: reserved and should be ignored by OSPM
|
||||
2: Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued.
|
||||
3-7: reserved and should be ignored by OSPM
|
||||
[0x15-0x17] reserved
|
||||
|
||||
write access:
|
||||
@ -31,14 +33,62 @@ Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
|
||||
[0xc-0x13] reserved, writes into it are ignored
|
||||
[0x14] Memory device control fields
|
||||
bits:
|
||||
0: reserved, OSPM must clear it before writing to register
|
||||
0: reserved, OSPM must clear it before writing to register.
|
||||
Due to BUG in versions prior 2.4 that field isn't cleared
|
||||
when other fields are written. Keep it reserved and don't
|
||||
try to reuse it.
|
||||
1: if set to 1 clears device insert event, set by OSPM
|
||||
after it has emitted device check event for the
|
||||
selected memory device
|
||||
2-7: reserved, OSPM must clear them before writing to register
|
||||
2: if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected memory device
|
||||
3: if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers memory device removal and calls _EJ0 method
|
||||
4-7: reserved, OSPM must clear them before writing to register
|
||||
|
||||
Selecting memory device slot beyond present range has no effect on platform:
|
||||
- write accesses to memory hot-plug registers not documented above are
|
||||
ignored
|
||||
- read accesses to memory hot-plug registers not documented above return
|
||||
all bits set to 1.
|
||||
|
||||
Memory hot remove process diagram:
|
||||
----------------------------------
|
||||
+-------------+ +-----------------------+ +------------------+
|
||||
| 1. QEMU | | 2. QEMU | |3. QEMU |
|
||||
| device_del +---->+ device unplug request +----->+Send SCI to guest,|
|
||||
| | | cb | |return control to |
|
||||
+-------------+ +-----------------------+ |management |
|
||||
+------------------+
|
||||
|
||||
+---------------------------------------------------------------------+
|
||||
|
||||
+---------------------+ +-------------------------+
|
||||
| OSPM: | remove event | OSPM: |
|
||||
| send Eject Request, | | Scan memory devices |
|
||||
| clear remove event +<-------------+ for event flags |
|
||||
| | | |
|
||||
+---------------------+ +-------------------------+
|
||||
|
|
||||
|
|
||||
+---------v--------+ +-----------------------+
|
||||
| Guest OS: | success | OSPM: |
|
||||
| process Ejection +----------->+ Execute _EJ0 method, |
|
||||
| request | | set eject bit in flags|
|
||||
+------------------+ +-----------------------+
|
||||
|failure |
|
||||
v v
|
||||
+------------------------+ +-----------------------+
|
||||
| OSPM: | | QEMU: |
|
||||
| set OST event & status | | call device unplug cb |
|
||||
| fields | | |
|
||||
+------------------------+ +-----------------------+
|
||||
| |
|
||||
v v
|
||||
+------------------+ +-------------------+
|
||||
|QEMU: | |QEMU: |
|
||||
|Send OST QMP event| |Send device deleted|
|
||||
| | |QMP event |
|
||||
+------------------+ | |
|
||||
+-------------------+
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <string.h>
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
|
||||
static GArray *build_alloc_array(void)
|
||||
{
|
||||
@ -635,9 +636,11 @@ Aml *aml_reserved_field(unsigned length)
|
||||
}
|
||||
|
||||
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
|
||||
Aml *aml_field(const char *name, AmlFieldFlags flags)
|
||||
Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule)
|
||||
{
|
||||
Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
|
||||
uint8_t flags = rule << 5 | type;
|
||||
|
||||
build_append_namestring(var->buf, "%s", name);
|
||||
build_append_byte(var->buf, flags);
|
||||
return var;
|
||||
@ -891,3 +894,60 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
||||
dec, addr_gran, addr_min, addr_max,
|
||||
addr_trans, len, flags);
|
||||
}
|
||||
|
||||
void
|
||||
build_header(GArray *linker, GArray *table_data,
|
||||
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
|
||||
{
|
||||
memcpy(&h->signature, sig, 4);
|
||||
h->length = cpu_to_le32(len);
|
||||
h->revision = rev;
|
||||
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
|
||||
memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
|
||||
memcpy(h->oem_table_id + 4, sig, 4);
|
||||
h->oem_revision = cpu_to_le32(1);
|
||||
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
|
||||
h->asl_compiler_revision = cpu_to_le32(1);
|
||||
h->checksum = 0;
|
||||
/* Checksum to be filled in by Guest linker */
|
||||
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
|
||||
table_data->data, h, len, &h->checksum);
|
||||
}
|
||||
|
||||
void *acpi_data_push(GArray *table_data, unsigned size)
|
||||
{
|
||||
unsigned off = table_data->len;
|
||||
g_array_set_size(table_data, off + size);
|
||||
return table_data->data + off;
|
||||
}
|
||||
|
||||
unsigned acpi_data_len(GArray *table)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2, 22, 0)
|
||||
assert(g_array_get_element_size(table) == 1);
|
||||
#endif
|
||||
return table->len;
|
||||
}
|
||||
|
||||
void acpi_add_table(GArray *table_offsets, GArray *table_data)
|
||||
{
|
||||
uint32_t offset = cpu_to_le32(table_data->len);
|
||||
g_array_append_val(table_offsets, offset);
|
||||
}
|
||||
|
||||
void acpi_build_tables_init(AcpiBuildTables *tables)
|
||||
{
|
||||
tables->rsdp = g_array_new(false, true /* clear */, 1);
|
||||
tables->table_data = g_array_new(false, true /* clear */, 1);
|
||||
tables->tcpalog = g_array_new(false, true /* clear */, 1);
|
||||
tables->linker = bios_linker_loader_init();
|
||||
}
|
||||
|
||||
void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
|
||||
{
|
||||
void *linker_data = bios_linker_loader_cleanup(tables->linker);
|
||||
g_free(linker_data);
|
||||
g_array_free(tables->rsdp, true);
|
||||
g_array_free(tables->table_data, true);
|
||||
g_array_free(tables->tcpalog, mfre);
|
||||
}
|
||||
|
@ -400,15 +400,26 @@ void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
|
||||
void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
if (pm->acpi_memory_hotplug.is_enabled &&
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq,
|
||||
&pm->acpi_memory_hotplug, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
if (pm->acpi_memory_hotplug.is_enabled &&
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "hw/acpi/pc-hotplug.h"
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "trace.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
@ -75,6 +76,7 @@ static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
|
||||
case 0x14: /* pack and return is_* fields */
|
||||
val |= mdev->is_enabled ? 1 : 0;
|
||||
val |= mdev->is_inserting ? 2 : 0;
|
||||
val |= mdev->is_removing ? 4 : 0;
|
||||
trace_mhp_acpi_read_flags(mem_st->selector, val);
|
||||
break;
|
||||
default:
|
||||
@ -90,6 +92,9 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
MemHotplugState *mem_st = opaque;
|
||||
MemStatus *mdev;
|
||||
ACPIOSTInfo *info;
|
||||
DeviceState *dev = NULL;
|
||||
HotplugHandler *hotplug_ctrl = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!mem_st->dev_count) {
|
||||
return;
|
||||
@ -127,13 +132,36 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
qapi_event_send_acpi_device_ost(info, &error_abort);
|
||||
qapi_free_ACPIOSTInfo(info);
|
||||
break;
|
||||
case 0x14:
|
||||
case 0x14: /* set is_* fields */
|
||||
mdev = &mem_st->devs[mem_st->selector];
|
||||
if (data & 2) { /* clear insert event */
|
||||
mdev->is_inserting = false;
|
||||
trace_mhp_acpi_clear_insert_evt(mem_st->selector);
|
||||
} else if (data & 4) {
|
||||
mdev->is_removing = false;
|
||||
trace_mhp_acpi_clear_remove_evt(mem_st->selector);
|
||||
} else if (data & 8) {
|
||||
if (!mdev->is_enabled) {
|
||||
trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
|
||||
break;
|
||||
}
|
||||
|
||||
dev = DEVICE(mdev->dimm);
|
||||
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
||||
/* call pc-dimm unplug cb */
|
||||
hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
|
||||
if (local_err) {
|
||||
trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector);
|
||||
qapi_event_send_mem_unplug_error(dev->id,
|
||||
error_get_pretty(local_err),
|
||||
&error_abort);
|
||||
break;
|
||||
}
|
||||
trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@ -163,29 +191,51 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io);
|
||||
}
|
||||
|
||||
void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp)
|
||||
/**
|
||||
* acpi_memory_slot_status:
|
||||
* @mem_st: memory hotplug state
|
||||
* @dev: device
|
||||
* @errp: set in case of an error
|
||||
*
|
||||
* Obtain a single memory slot status.
|
||||
*
|
||||
* This function will be called by memory unplug request cb and unplug cb.
|
||||
*/
|
||||
static MemStatus *
|
||||
acpi_memory_slot_status(MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
MemStatus *mdev;
|
||||
Error *local_err = NULL;
|
||||
int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
|
||||
&local_err);
|
||||
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (slot >= mem_st->dev_count) {
|
||||
char *dev_path = object_get_canonical_path(OBJECT(dev));
|
||||
error_setg(errp, "acpi_memory_plug_cb: "
|
||||
error_setg(errp, "acpi_memory_slot_status: "
|
||||
"device [%s] returned invalid memory slot[%d]",
|
||||
dev_path, slot);
|
||||
g_free(dev_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &mem_st->devs[slot];
|
||||
}
|
||||
|
||||
void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
MemStatus *mdev;
|
||||
|
||||
mdev = acpi_memory_slot_status(mem_st, dev, errp);
|
||||
if (!mdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
mdev = &mem_st->devs[slot];
|
||||
mdev->dimm = dev;
|
||||
mdev->is_enabled = true;
|
||||
mdev->is_inserting = true;
|
||||
@ -196,6 +246,38 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
||||
return;
|
||||
}
|
||||
|
||||
void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
|
||||
MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
MemStatus *mdev;
|
||||
|
||||
mdev = acpi_memory_slot_status(mem_st, dev, errp);
|
||||
if (!mdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
mdev->is_removing = true;
|
||||
|
||||
/* Do ACPI magic */
|
||||
ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS;
|
||||
acpi_update_sci(ar, irq);
|
||||
}
|
||||
|
||||
void acpi_memory_unplug_cb(MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
MemStatus *mdev;
|
||||
|
||||
mdev = acpi_memory_slot_status(mem_st, dev, errp);
|
||||
if (!mdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
mdev->is_enabled = false;
|
||||
mdev->dimm = NULL;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_memhp_sts = {
|
||||
.name = "memory hotplug device state",
|
||||
.version_id = 1,
|
||||
|
@ -361,7 +361,11 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
{
|
||||
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||
if (s->acpi_memory_hotplug.is_enabled &&
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug,
|
||||
dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||
acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
|
||||
errp);
|
||||
} else {
|
||||
@ -373,8 +377,15 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
|
||||
|
||||
if (s->acpi_memory_hotplug.is_enabled &&
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
|
||||
|
@ -273,7 +273,7 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
dev->alias_required_for_version = required_for_version;
|
||||
}
|
||||
|
||||
static HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
|
||||
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
|
||||
{
|
||||
HotplugHandler *hotplug_ctrl = NULL;
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "hw/i386/pc.h"
|
||||
#include "target-i386/cpu.h"
|
||||
#include "hw/timer/hpet.h"
|
||||
#include "hw/i386/acpi-defs.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
@ -68,9 +68,6 @@
|
||||
|
||||
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
||||
|
||||
/* Reserve RAM space for tables: add another order of magnitude. */
|
||||
#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
|
||||
|
||||
/* #define DEBUG_ACPI_BUILD */
|
||||
#ifdef DEBUG_ACPI_BUILD
|
||||
#define ACPI_BUILD_DPRINTF(fmt, ...) \
|
||||
@ -265,51 +262,8 @@ static void acpi_get_pci_info(PcPciInfo *info)
|
||||
NULL);
|
||||
}
|
||||
|
||||
#define ACPI_BUILD_APPNAME "Bochs"
|
||||
#define ACPI_BUILD_APPNAME6 "BOCHS "
|
||||
#define ACPI_BUILD_APPNAME4 "BXPC"
|
||||
|
||||
#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
|
||||
#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
|
||||
#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
|
||||
|
||||
static void
|
||||
build_header(GArray *linker, GArray *table_data,
|
||||
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
|
||||
{
|
||||
memcpy(&h->signature, sig, 4);
|
||||
h->length = cpu_to_le32(len);
|
||||
h->revision = rev;
|
||||
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
|
||||
memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
|
||||
memcpy(h->oem_table_id + 4, sig, 4);
|
||||
h->oem_revision = cpu_to_le32(1);
|
||||
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
|
||||
h->asl_compiler_revision = cpu_to_le32(1);
|
||||
h->checksum = 0;
|
||||
/* Checksum to be filled in by Guest linker */
|
||||
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
|
||||
table_data->data, h, len, &h->checksum);
|
||||
}
|
||||
|
||||
/* End here */
|
||||
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
|
||||
|
||||
static inline void *acpi_data_push(GArray *table_data, unsigned size)
|
||||
{
|
||||
unsigned off = table_data->len;
|
||||
g_array_set_size(table_data, off + size);
|
||||
return table_data->data + off;
|
||||
}
|
||||
|
||||
static unsigned acpi_data_len(GArray *table)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2, 22, 0)
|
||||
assert(g_array_get_element_size(table) == 1);
|
||||
#endif
|
||||
return table->len;
|
||||
}
|
||||
|
||||
static void acpi_align_size(GArray *blob, unsigned align)
|
||||
{
|
||||
/* Align size to multiple of given size. This reduces the chance
|
||||
@ -318,12 +272,6 @@ static void acpi_align_size(GArray *blob, unsigned align)
|
||||
g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
|
||||
}
|
||||
|
||||
static inline void acpi_add_table(GArray *table_offsets, GArray *table_data)
|
||||
{
|
||||
uint32_t offset = cpu_to_le32(table_data->len);
|
||||
g_array_append_val(table_offsets, offset);
|
||||
}
|
||||
|
||||
/* FACS */
|
||||
static void
|
||||
build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
||||
@ -796,7 +744,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
|
||||
aml_append(dev, aml_operation_region("PEOR", aml_system_io,
|
||||
misc->pvpanic_port, 1));
|
||||
field = aml_field("PEOR", aml_byte_acc);
|
||||
field = aml_field("PEOR", aml_byte_acc, aml_preserve);
|
||||
aml_append(field, aml_named_field("PEPT", 8));
|
||||
aml_append(dev, field);
|
||||
|
||||
@ -813,7 +761,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
aml_append(ssdt, scope);
|
||||
}
|
||||
|
||||
sb_scope = aml_scope("_SB");
|
||||
sb_scope = aml_scope("\\_SB");
|
||||
{
|
||||
/* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */
|
||||
dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE));
|
||||
@ -833,7 +781,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
/* declare CPU hotplug MMIO region and PRS field to access it */
|
||||
aml_append(sb_scope, aml_operation_region(
|
||||
"PRST", aml_system_io, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
|
||||
field = aml_field("PRST", aml_byte_acc);
|
||||
field = aml_field("PRST", aml_byte_acc, aml_preserve);
|
||||
aml_append(field, aml_named_field("PRS", 256));
|
||||
aml_append(sb_scope, field);
|
||||
|
||||
@ -907,7 +855,8 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
pm->mem_hp_io_base, pm->mem_hp_io_len)
|
||||
);
|
||||
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc);
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
|
||||
aml_preserve);
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32));
|
||||
aml_append(field, /* read only */
|
||||
@ -920,16 +869,24 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc);
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc,
|
||||
aml_write_as_zeros);
|
||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||
aml_append(field, /* 1 if enabled, read only */
|
||||
aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1));
|
||||
aml_append(field,
|
||||
/*(read) 1 if has a insert event. (write) 1 to clear event */
|
||||
aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1));
|
||||
aml_append(field,
|
||||
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||
aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1));
|
||||
aml_append(field,
|
||||
/* initiates device eject, write only */
|
||||
aml_named_field(stringify(MEMORY_SLOT_EJECT), 1));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc);
|
||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
|
||||
aml_preserve);
|
||||
aml_append(field, /* DIMM selector, write only */
|
||||
aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32));
|
||||
aml_append(field, /* _OST event code, write only */
|
||||
@ -970,11 +927,17 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1);
|
||||
s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD);
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(sb_scope, dev);
|
||||
}
|
||||
|
||||
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ...
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
|
||||
*/
|
||||
method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2);
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
@ -1293,31 +1256,6 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
||||
return rsdp_table;
|
||||
}
|
||||
|
||||
typedef
|
||||
struct AcpiBuildTables {
|
||||
GArray *table_data;
|
||||
GArray *rsdp;
|
||||
GArray *tcpalog;
|
||||
GArray *linker;
|
||||
} AcpiBuildTables;
|
||||
|
||||
static inline void acpi_build_tables_init(AcpiBuildTables *tables)
|
||||
{
|
||||
tables->rsdp = g_array_new(false, true /* clear */, 1);
|
||||
tables->table_data = g_array_new(false, true /* clear */, 1);
|
||||
tables->tcpalog = g_array_new(false, true /* clear */, 1);
|
||||
tables->linker = bios_linker_loader_init();
|
||||
}
|
||||
|
||||
static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
|
||||
{
|
||||
void *linker_data = bios_linker_loader_cleanup(tables->linker);
|
||||
g_free(linker_data);
|
||||
g_array_free(tables->rsdp, true);
|
||||
g_array_free(tables->table_data, true);
|
||||
g_array_free(tables->tcpalog, mfre);
|
||||
}
|
||||
|
||||
typedef
|
||||
struct AcpiBuildState {
|
||||
/* Copy of table in RAM (for patching). */
|
||||
|
@ -29,6 +29,8 @@
|
||||
External(MEMORY_SLOT_PROXIMITY, FieldUnitObj) // read only
|
||||
External(MEMORY_SLOT_ENABLED, FieldUnitObj) // 1 if enabled, read only
|
||||
External(MEMORY_SLOT_INSERT_EVENT, FieldUnitObj) // (read) 1 if has a insert event. (write) 1 to clear event
|
||||
External(MEMORY_SLOT_REMOVE_EVENT, FieldUnitObj) // (read) 1 if has a remove event. (write) 1 to clear event
|
||||
External(MEMORY_SLOT_EJECT, FieldUnitObj) // initiates device eject, write only
|
||||
External(MEMORY_SLOT_SLECTOR, FieldUnitObj) // DIMM selector, write only
|
||||
External(MEMORY_SLOT_OST_EVENT, FieldUnitObj) // _OST event code, write only
|
||||
External(MEMORY_SLOT_OST_STATUS, FieldUnitObj) // _OST status code, write only
|
||||
@ -55,8 +57,10 @@
|
||||
If (LEqual(MEMORY_SLOT_INSERT_EVENT, One)) { // Memory device needs check
|
||||
MEMORY_SLOT_NOTIFY_METHOD(Local0, 1)
|
||||
Store(1, MEMORY_SLOT_INSERT_EVENT)
|
||||
} Elseif (LEqual(MEMORY_SLOT_REMOVE_EVENT, One)) { // Ejection request
|
||||
MEMORY_SLOT_NOTIFY_METHOD(Local0, 3)
|
||||
Store(1, MEMORY_SLOT_REMOVE_EVENT)
|
||||
}
|
||||
// TODO: handle memory eject request
|
||||
Add(Local0, One, Local0) // goto next DIMM
|
||||
}
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
@ -156,5 +160,12 @@
|
||||
Store(Arg2, MEMORY_SLOT_OST_STATUS)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
}
|
||||
|
||||
Method(MEMORY_SLOT_EJECT_METHOD, 2) {
|
||||
Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
|
||||
Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
|
||||
Store(1, MEMORY_SLOT_EJECT)
|
||||
Release(MEMORY_SLOT_LOCK)
|
||||
}
|
||||
} // Device()
|
||||
} // Scope()
|
||||
|
62
hw/i386/pc.c
62
hw/i386/pc.c
@ -1677,6 +1677,52 @@ out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void pc_dimm_unplug_request(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
HotplugHandlerClass *hhc;
|
||||
Error *local_err = NULL;
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
|
||||
if (!pcms->acpi_dev) {
|
||||
error_setg(&local_err,
|
||||
"memory hotplug is not enabled: missing acpi device");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
||||
hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void pc_dimm_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||
HotplugHandlerClass *hhc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
||||
hhc->unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
memory_region_del_subregion(&pcms->hotplug_memory, mr);
|
||||
vmstate_unregister_ram(mr, dev);
|
||||
|
||||
object_unparent(OBJECT(dev));
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void pc_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
@ -1719,15 +1765,23 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_dimm_unplug_request(hotplug_dev, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_dimm_unplug(hotplug_dev, dev, errp);
|
||||
} else {
|
||||
error_setg(errp, "acpi: device unplug for not supported device"
|
||||
" type: %s", object_get_typename(OBJECT(dev)));
|
||||
}
|
||||
}
|
||||
|
||||
static HotplugHandler *pc_get_hotpug_handler(MachineState *machine,
|
||||
|
@ -310,8 +310,13 @@ static void pc_init_pci(MachineState *machine)
|
||||
pc_init1(machine, 1, 1);
|
||||
}
|
||||
|
||||
static void pc_compat_2_3(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void pc_compat_2_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_3(machine);
|
||||
rsdp_in_ram = false;
|
||||
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
|
||||
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
|
||||
@ -413,6 +418,12 @@ static void pc_compat_1_2(MachineState *machine)
|
||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
||||
}
|
||||
|
||||
static void pc_init_pci_2_3(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_3(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_2_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_2(machine);
|
||||
@ -512,19 +523,28 @@ static void pc_xen_hvm_init(MachineState *machine)
|
||||
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
||||
.hot_add_cpu = pc_hot_add_cpu
|
||||
|
||||
#define PC_I440FX_2_3_MACHINE_OPTIONS \
|
||||
#define PC_I440FX_2_4_MACHINE_OPTIONS \
|
||||
PC_I440FX_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
||||
.default_display = "std"
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_3 = {
|
||||
PC_I440FX_2_3_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.3",
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_4 = {
|
||||
PC_I440FX_2_4_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.4",
|
||||
.alias = "pc",
|
||||
.init = pc_init_pci,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
#define PC_I440FX_2_3_MACHINE_OPTIONS PC_I440FX_2_4_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_3 = {
|
||||
PC_I440FX_2_3_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.3",
|
||||
.init = pc_init_pci_2_3,
|
||||
};
|
||||
|
||||
#define PC_I440FX_2_2_MACHINE_OPTIONS PC_I440FX_2_3_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_2 = {
|
||||
@ -970,6 +990,7 @@ static QEMUMachine xenfv_machine = {
|
||||
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_4);
|
||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_3);
|
||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
|
||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
|
||||
|
@ -289,8 +289,13 @@ static void pc_q35_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_compat_2_3(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void pc_compat_2_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_3(machine);
|
||||
rsdp_in_ram = false;
|
||||
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
|
||||
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
|
||||
@ -361,6 +366,12 @@ static void pc_compat_1_4(MachineState *machine)
|
||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||
}
|
||||
|
||||
static void pc_q35_init_2_3(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_3(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
static void pc_q35_init_2_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_2(machine);
|
||||
@ -410,16 +421,24 @@ static void pc_q35_init_1_4(MachineState *machine)
|
||||
.hot_add_cpu = pc_hot_add_cpu, \
|
||||
.units_per_default_bus = 1
|
||||
|
||||
#define PC_Q35_2_3_MACHINE_OPTIONS \
|
||||
#define PC_Q35_2_4_MACHINE_OPTIONS \
|
||||
PC_Q35_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
||||
.default_display = "std"
|
||||
|
||||
static QEMUMachine pc_q35_machine_v2_4 = {
|
||||
PC_Q35_2_4_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-2.4",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
};
|
||||
|
||||
#define PC_Q35_2_3_MACHINE_OPTIONS PC_Q35_2_4_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_q35_machine_v2_3 = {
|
||||
PC_Q35_2_3_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-2.3",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
.init = pc_q35_init_2_3,
|
||||
};
|
||||
|
||||
#define PC_Q35_2_2_MACHINE_OPTIONS PC_Q35_2_3_MACHINE_OPTIONS
|
||||
@ -506,6 +525,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
|
||||
|
||||
static void pc_q35_machine_init(void)
|
||||
{
|
||||
qemu_register_pc_machine(&pc_q35_machine_v2_4);
|
||||
qemu_register_pc_machine(&pc_q35_machine_v2_3);
|
||||
qemu_register_pc_machine(&pc_q35_machine_v2_2);
|
||||
qemu_register_pc_machine(&pc_q35_machine_v2_1);
|
||||
|
@ -263,6 +263,13 @@ static void vhost_net_stop_one(struct vhost_net *net,
|
||||
&file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
} else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
|
||||
NULL);
|
||||
assert(r >= 0);
|
||||
}
|
||||
}
|
||||
if (net->nc->info->poll) {
|
||||
net->nc->info->poll(net->nc, true);
|
||||
|
@ -446,6 +446,9 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
NetClientState *nc = qemu_get_queue(n->nic);
|
||||
|
||||
/* Firstly sync all virtio-net possible supported features */
|
||||
features |= n->host_features;
|
||||
|
||||
virtio_add_feature(&features, VIRTIO_NET_F_MAC);
|
||||
|
||||
if (!peer_has_vnet_hdr(n)) {
|
||||
@ -1309,7 +1312,7 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
|
||||
|
||||
n->multiqueue = multiqueue;
|
||||
|
||||
for (i = 2; i <= n->max_queues * 2 + 1; i++) {
|
||||
for (i = 2; i < n->max_queues * 2 + 1; i++) {
|
||||
virtio_del_queue(vdev, i);
|
||||
}
|
||||
|
||||
@ -1552,7 +1555,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
|
||||
vdev, idx, mask);
|
||||
}
|
||||
|
||||
void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
|
||||
static void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
|
||||
{
|
||||
int i, config_size = 0;
|
||||
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
|
||||
@ -1585,6 +1588,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
NetClientState *nc;
|
||||
int i;
|
||||
|
||||
virtio_net_set_config_size(n, n->host_features);
|
||||
virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
|
||||
|
||||
n->max_queues = MAX(n->nic_conf.peers.queues, 1);
|
||||
@ -1721,6 +1725,7 @@ static void virtio_net_instance_init(Object *obj)
|
||||
}
|
||||
|
||||
static Property virtio_net_properties[] = {
|
||||
DEFINE_VIRTIO_NET_FEATURES(VirtIONet, host_features),
|
||||
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
|
||||
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
|
||||
TX_TIMER_INTERVAL),
|
||||
|
@ -295,29 +295,37 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
{
|
||||
int ret;
|
||||
char *name;
|
||||
uint32_t bar_size = 4096;
|
||||
uint32_t bar_pba_offset = bar_size / 2;
|
||||
uint32_t bar_pba_size = (nentries / 8 + 1) * 8;
|
||||
|
||||
/*
|
||||
* Migration compatibility dictates that this remains a 4k
|
||||
* BAR with the vector table in the lower half and PBA in
|
||||
* the upper half. Do not use these elsewhere!
|
||||
* the upper half for nentries which is lower or equal to 128.
|
||||
* No need to care about using more than 65 entries for legacy
|
||||
* machine types who has at most 64 queues.
|
||||
*/
|
||||
#define MSIX_EXCLUSIVE_BAR_SIZE 4096
|
||||
#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0
|
||||
#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
|
||||
#define MSIX_EXCLUSIVE_CAP_OFFSET 0
|
||||
if (nentries * PCI_MSIX_ENTRY_SIZE > bar_pba_offset) {
|
||||
bar_pba_offset = nentries * PCI_MSIX_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
|
||||
return -EINVAL;
|
||||
if (bar_pba_offset + bar_pba_size > 4096) {
|
||||
bar_size = bar_pba_offset + bar_pba_size;
|
||||
}
|
||||
|
||||
if (bar_size & (bar_size - 1)) {
|
||||
bar_size = 1 << qemu_fls(bar_size);
|
||||
}
|
||||
|
||||
name = g_strdup_printf("%s-msix", dev->name);
|
||||
memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, MSIX_EXCLUSIVE_BAR_SIZE);
|
||||
memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, bar_size);
|
||||
g_free(name);
|
||||
|
||||
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
|
||||
MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar,
|
||||
bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET,
|
||||
MSIX_EXCLUSIVE_CAP_OFFSET);
|
||||
0, &dev->msix_exclusive_bar,
|
||||
bar_nr, bar_pba_offset,
|
||||
0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
43
hw/pci/pci.c
43
hw/pci/pci.c
@ -1615,28 +1615,32 @@ static const char * const pci_nic_names[] = {
|
||||
};
|
||||
|
||||
/* Initialize a PCI NIC. */
|
||||
static PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr,
|
||||
Error **errp)
|
||||
const char *default_devaddr)
|
||||
{
|
||||
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
|
||||
Error *err = NULL;
|
||||
PCIBus *bus;
|
||||
int devfn;
|
||||
PCIDevice *pci_dev;
|
||||
DeviceState *dev;
|
||||
int devfn;
|
||||
int i;
|
||||
|
||||
if (qemu_show_nic_models(nd->model, pci_nic_models)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = qemu_find_nic_model(nd, pci_nic_models, default_model);
|
||||
if (i < 0)
|
||||
return NULL;
|
||||
if (i < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
|
||||
if (!bus) {
|
||||
error_report("Invalid PCI device address %s for device %s",
|
||||
devaddr, pci_nic_names[i]);
|
||||
return NULL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
|
||||
@ -1645,31 +1649,12 @@ static PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
|
||||
|
||||
object_property_set_bool(OBJECT(dev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
error_report_err(err);
|
||||
object_unparent(OBJECT(dev));
|
||||
return NULL;
|
||||
}
|
||||
return pci_dev;
|
||||
}
|
||||
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr)
|
||||
{
|
||||
Error *err = NULL;
|
||||
PCIDevice *res;
|
||||
|
||||
if (qemu_show_nic_models(nd->model, pci_nic_models))
|
||||
exit(0);
|
||||
|
||||
res = pci_nic_init(nd, rootbus, default_model, default_devaddr, &err);
|
||||
if (!res) {
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
return res;
|
||||
|
||||
return pci_dev;
|
||||
}
|
||||
|
||||
PCIDevice *pci_vga_init(PCIBus *bus)
|
||||
|
@ -1825,6 +1825,38 @@ static const TypeInfo spapr_machine_info = {
|
||||
#define SPAPR_COMPAT_2_1 \
|
||||
SPAPR_COMPAT_2_2
|
||||
|
||||
static void spapr_compat_2_3(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static void spapr_compat_2_2(Object *obj)
|
||||
{
|
||||
spapr_compat_2_3(obj);
|
||||
}
|
||||
|
||||
static void spapr_compat_2_1(Object *obj)
|
||||
{
|
||||
spapr_compat_2_2(obj);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_3_instance_init(Object *obj)
|
||||
{
|
||||
spapr_compat_2_3(obj);
|
||||
spapr_machine_initfn(obj);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_2_instance_init(Object *obj)
|
||||
{
|
||||
spapr_compat_2_2(obj);
|
||||
spapr_machine_initfn(obj);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_1_instance_init(Object *obj)
|
||||
{
|
||||
spapr_compat_2_1(obj);
|
||||
spapr_machine_initfn(obj);
|
||||
}
|
||||
|
||||
static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
@ -1843,6 +1875,7 @@ static const TypeInfo spapr_machine_2_1_info = {
|
||||
.name = TYPE_SPAPR_MACHINE "2.1",
|
||||
.parent = TYPE_SPAPR_MACHINE,
|
||||
.class_init = spapr_machine_2_1_class_init,
|
||||
.instance_init = spapr_machine_2_1_instance_init,
|
||||
};
|
||||
|
||||
static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
|
||||
@ -1862,6 +1895,7 @@ static const TypeInfo spapr_machine_2_2_info = {
|
||||
.name = TYPE_SPAPR_MACHINE "2.2",
|
||||
.parent = TYPE_SPAPR_MACHINE,
|
||||
.class_init = spapr_machine_2_2_class_init,
|
||||
.instance_init = spapr_machine_2_2_instance_init,
|
||||
};
|
||||
|
||||
static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data)
|
||||
@ -1870,14 +1904,29 @@ static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
mc->name = "pseries-2.3";
|
||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.3";
|
||||
mc->alias = "pseries";
|
||||
mc->is_default = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_2_3_info = {
|
||||
.name = TYPE_SPAPR_MACHINE "2.3",
|
||||
.parent = TYPE_SPAPR_MACHINE,
|
||||
.class_init = spapr_machine_2_3_class_init,
|
||||
.instance_init = spapr_machine_2_3_instance_init,
|
||||
};
|
||||
|
||||
static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = "pseries-2.4";
|
||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4";
|
||||
mc->alias = "pseries";
|
||||
mc->is_default = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_2_4_info = {
|
||||
.name = TYPE_SPAPR_MACHINE "2.4",
|
||||
.parent = TYPE_SPAPR_MACHINE,
|
||||
.class_init = spapr_machine_2_4_class_init,
|
||||
};
|
||||
|
||||
static void spapr_machine_register_types(void)
|
||||
@ -1886,6 +1935,7 @@ static void spapr_machine_register_types(void)
|
||||
type_register_static(&spapr_machine_2_1_info);
|
||||
type_register_static(&spapr_machine_2_2_info);
|
||||
type_register_static(&spapr_machine_2_3_info);
|
||||
type_register_static(&spapr_machine_2_4_info);
|
||||
}
|
||||
|
||||
type_init(spapr_machine_register_types)
|
||||
|
@ -155,7 +155,6 @@ static void s390_virtio_net_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
virtio_net_set_config_size(&dev->vdev, s390_dev->host_features);
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
@ -537,18 +536,12 @@ static unsigned virtio_s390_get_features(DeviceState *d)
|
||||
|
||||
/**************** S390 Virtio Bus Device Descriptions *******************/
|
||||
|
||||
static Property s390_virtio_net_properties[] = {
|
||||
DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = s390_virtio_net_realize;
|
||||
dc->props = s390_virtio_net_properties;
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
}
|
||||
|
||||
@ -657,18 +650,12 @@ static const TypeInfo virtio_s390_device_info = {
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static Property s390_virtio_scsi_properties[] = {
|
||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = s390_virtio_scsi_realize;
|
||||
dc->props = s390_virtio_scsi_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
||||
|
||||
virtio_queue_set_addr(vdev, index, addr);
|
||||
if (!addr) {
|
||||
virtio_queue_set_vector(vdev, index, 0);
|
||||
virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
|
||||
} else {
|
||||
/* Fail if we don't have a big enough queue. */
|
||||
/* TODO: Add interface to handle vring.num changing */
|
||||
@ -805,7 +805,6 @@ static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
@ -1441,7 +1440,6 @@ static void virtio_ccw_device_unplugged(DeviceState *d)
|
||||
|
||||
static Property virtio_ccw_net_properties[] = {
|
||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@ -1550,7 +1548,6 @@ static const TypeInfo virtio_ccw_balloon = {
|
||||
|
||||
static Property virtio_ccw_scsi_properties[] = {
|
||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@ -631,6 +631,10 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
|
||||
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
|
||||
uint32_t requested_features)
|
||||
{
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
|
||||
/* Firstly sync all virtio-scsi possible supported features */
|
||||
requested_features |= s->host_features;
|
||||
return requested_features;
|
||||
}
|
||||
|
||||
@ -945,6 +949,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
|
||||
|
||||
static Property virtio_scsi_properties[] = {
|
||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf),
|
||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOSCSI, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -630,28 +630,30 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int ret, queue_no;
|
||||
VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
|
||||
int ret, index, unmasked = 0;
|
||||
|
||||
for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
|
||||
if (!virtio_queue_get_num(vdev, queue_no)) {
|
||||
while (vq) {
|
||||
index = virtio_get_queue_index(vq);
|
||||
if (!virtio_queue_get_num(vdev, index)) {
|
||||
break;
|
||||
}
|
||||
if (virtio_queue_vector(vdev, queue_no) != vector) {
|
||||
continue;
|
||||
}
|
||||
ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
|
||||
ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
|
||||
if (ret < 0) {
|
||||
goto undo;
|
||||
}
|
||||
vq = virtio_vector_next_queue(vq);
|
||||
++unmasked;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
undo:
|
||||
while (--queue_no >= 0) {
|
||||
if (virtio_queue_vector(vdev, queue_no) != vector) {
|
||||
continue;
|
||||
}
|
||||
virtio_pci_vq_vector_mask(proxy, queue_no, vector);
|
||||
vq = virtio_vector_first_queue(vdev, vector);
|
||||
while (vq && --unmasked >= 0) {
|
||||
index = virtio_get_queue_index(vq);
|
||||
virtio_pci_vq_vector_mask(proxy, index, vector);
|
||||
vq = virtio_vector_next_queue(vq);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -660,16 +662,16 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int queue_no;
|
||||
VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
|
||||
int index;
|
||||
|
||||
for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
|
||||
if (!virtio_queue_get_num(vdev, queue_no)) {
|
||||
while (vq) {
|
||||
index = virtio_get_queue_index(vq);
|
||||
if (!virtio_queue_get_num(vdev, index)) {
|
||||
break;
|
||||
}
|
||||
if (virtio_queue_vector(vdev, queue_no) != vector) {
|
||||
continue;
|
||||
}
|
||||
virtio_pci_vq_vector_mask(proxy, queue_no, vector);
|
||||
virtio_pci_vq_vector_mask(proxy, index, vector);
|
||||
vq = virtio_vector_next_queue(vq);
|
||||
}
|
||||
}
|
||||
|
||||
@ -908,6 +910,13 @@ static const TypeInfo virtio_9p_pci_info = {
|
||||
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
|
||||
*/
|
||||
|
||||
static int virtio_pci_query_nvectors(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
|
||||
return proxy->nvectors;
|
||||
}
|
||||
|
||||
/* This is called by virtio-bus just after the device is plugged. */
|
||||
static void virtio_pci_device_plugged(DeviceState *d)
|
||||
{
|
||||
@ -1078,7 +1087,6 @@ static Property virtio_scsi_pci_properties[] = {
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -1360,7 +1368,6 @@ static Property virtio_net_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -1370,7 +1377,6 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features);
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
@ -1498,6 +1504,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
|
||||
k->vmstate_change = virtio_pci_vmstate_change;
|
||||
k->device_plugged = virtio_pci_device_plugged;
|
||||
k->device_unplugged = virtio_pci_device_unplugged;
|
||||
k->query_nvectors = virtio_pci_query_nvectors;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_pci_bus_info = {
|
||||
|
@ -89,6 +89,7 @@ struct VirtQueue
|
||||
VirtIODevice *vdev;
|
||||
EventNotifier guest_notifier;
|
||||
EventNotifier host_notifier;
|
||||
QLIST_ENTRY(VirtQueue) node;
|
||||
};
|
||||
|
||||
/* virt queue functions */
|
||||
@ -605,7 +606,7 @@ void virtio_reset(void *opaque)
|
||||
vdev->vq[i].vring.used = 0;
|
||||
vdev->vq[i].last_avail_idx = 0;
|
||||
vdev->vq[i].pa = 0;
|
||||
vdev->vq[i].vector = VIRTIO_NO_VECTOR;
|
||||
virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
|
||||
vdev->vq[i].signalled_used = 0;
|
||||
vdev->vq[i].signalled_used_valid = false;
|
||||
vdev->vq[i].notification = true;
|
||||
@ -730,6 +731,16 @@ void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
|
||||
virtqueue_init(&vdev->vq[n]);
|
||||
}
|
||||
|
||||
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector)
|
||||
{
|
||||
return QLIST_FIRST(&vdev->vector_queues[vector]);
|
||||
}
|
||||
|
||||
VirtQueue *virtio_vector_next_queue(VirtQueue *vq)
|
||||
{
|
||||
return QLIST_NEXT(vq, node);
|
||||
}
|
||||
|
||||
int virtio_queue_get_num(VirtIODevice *vdev, int n)
|
||||
{
|
||||
return vdev->vq[n].vring.num;
|
||||
@ -780,8 +791,19 @@ uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
|
||||
|
||||
void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
|
||||
{
|
||||
if (n < VIRTIO_PCI_QUEUE_MAX)
|
||||
VirtQueue *vq = &vdev->vq[n];
|
||||
|
||||
if (n < VIRTIO_PCI_QUEUE_MAX) {
|
||||
if (vdev->vector_queues &&
|
||||
vdev->vq[n].vector != VIRTIO_NO_VECTOR) {
|
||||
QLIST_REMOVE(vq, node);
|
||||
}
|
||||
vdev->vq[n].vector = vector;
|
||||
if (vdev->vector_queues &&
|
||||
vector != VIRTIO_NO_VECTOR) {
|
||||
QLIST_INSERT_HEAD(&vdev->vector_queues[vector], vq, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
|
||||
@ -1088,6 +1110,7 @@ void virtio_cleanup(VirtIODevice *vdev)
|
||||
qemu_del_vm_change_state_handler(vdev->vmstate);
|
||||
g_free(vdev->config);
|
||||
g_free(vdev->vq);
|
||||
g_free(vdev->vector_queues);
|
||||
}
|
||||
|
||||
static void virtio_vmstate_change(void *opaque, int running, RunState state)
|
||||
@ -1125,7 +1148,16 @@ void virtio_instance_init_common(Object *proxy_obj, void *data,
|
||||
void virtio_init(VirtIODevice *vdev, const char *name,
|
||||
uint16_t device_id, size_t config_size)
|
||||
{
|
||||
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int i;
|
||||
int nvectors = k->query_nvectors ? k->query_nvectors(qbus->parent) : 0;
|
||||
|
||||
if (nvectors) {
|
||||
vdev->vector_queues =
|
||||
g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
|
||||
}
|
||||
|
||||
vdev->device_id = device_id;
|
||||
vdev->status = 0;
|
||||
vdev->isr = 0;
|
||||
|
@ -4,6 +4,18 @@
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include "qemu/compiler.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
|
||||
/* Reserve RAM space for tables: add another order of magnitude. */
|
||||
#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
|
||||
|
||||
#define ACPI_BUILD_APPNAME "Bochs"
|
||||
#define ACPI_BUILD_APPNAME6 "BOCHS "
|
||||
#define ACPI_BUILD_APPNAME4 "BXPC"
|
||||
|
||||
#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
|
||||
#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
|
||||
#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
|
||||
|
||||
typedef enum {
|
||||
AML_NO_OPCODE = 0,/* has only data */
|
||||
@ -35,7 +47,13 @@ typedef enum {
|
||||
aml_dword_acc = 3,
|
||||
aml_qword_acc = 4,
|
||||
aml_buffer_acc = 5,
|
||||
} AmlFieldFlags;
|
||||
} AmlAccessType;
|
||||
|
||||
typedef enum {
|
||||
aml_preserve = 0,
|
||||
aml_write_as_ones = 1,
|
||||
aml_write_as_zeros = 2,
|
||||
} AmlUpdateRule;
|
||||
|
||||
typedef enum {
|
||||
aml_system_memory = 0x00,
|
||||
@ -93,6 +111,14 @@ typedef enum {
|
||||
aml_ReadWrite = 1,
|
||||
} AmlReadAndWrite;
|
||||
|
||||
typedef
|
||||
struct AcpiBuildTables {
|
||||
GArray *table_data;
|
||||
GArray *rsdp;
|
||||
GArray *tcpalog;
|
||||
GArray *linker;
|
||||
} AcpiBuildTables;
|
||||
|
||||
/**
|
||||
* init_aml_allocator:
|
||||
*
|
||||
@ -120,7 +146,7 @@ void free_aml_allocator(void);
|
||||
* Joins Aml elements together and helps to construct AML tables
|
||||
* Examle of usage:
|
||||
* Aml *table = aml_def_block("SSDT", ...);
|
||||
* Aml *sb = aml_scope("\_SB");
|
||||
* Aml *sb = aml_scope("\\_SB");
|
||||
* Aml *dev = aml_device("PCI0");
|
||||
*
|
||||
* aml_append(dev, aml_name_decl("HID", aml_eisaid("PNP0A03")));
|
||||
@ -185,7 +211,16 @@ Aml *aml_if(Aml *predicate);
|
||||
Aml *aml_package(uint8_t num_elements);
|
||||
Aml *aml_buffer(void);
|
||||
Aml *aml_resource_template(void);
|
||||
Aml *aml_field(const char *name, AmlFieldFlags flags);
|
||||
Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule);
|
||||
Aml *aml_varpackage(uint32_t num_elements);
|
||||
|
||||
void
|
||||
build_header(GArray *linker, GArray *table_data,
|
||||
AcpiTableHeader *h, const char *sig, int len, uint8_t rev);
|
||||
void *acpi_data_push(GArray *table_data, unsigned size);
|
||||
unsigned acpi_data_len(GArray *table);
|
||||
void acpi_add_table(GArray *table_offsets, GArray *table_data);
|
||||
void acpi_build_tables_init(AcpiBuildTables *tables);
|
||||
void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre);
|
||||
|
||||
#endif
|
||||
|
@ -7,10 +7,17 @@
|
||||
|
||||
#define ACPI_MEMORY_HOTPLUG_STATUS 8
|
||||
|
||||
/**
|
||||
* MemStatus:
|
||||
* @is_removing: the memory device in slot has been requested to be ejected.
|
||||
*
|
||||
* This structure stores memory device's status.
|
||||
*/
|
||||
typedef struct MemStatus {
|
||||
DeviceState *dimm;
|
||||
bool is_enabled;
|
||||
bool is_inserting;
|
||||
bool is_removing;
|
||||
uint32_t ost_event;
|
||||
uint32_t ost_status;
|
||||
} MemStatus;
|
||||
@ -28,6 +35,11 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
|
||||
void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp);
|
||||
void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
|
||||
MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp);
|
||||
void acpi_memory_unplug_cb(MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp);
|
||||
|
||||
extern const VMStateDescription vmstate_memory_hotplug;
|
||||
#define VMSTATE_MEMORY_HOTPLUG(memhp, state) \
|
||||
|
@ -43,6 +43,8 @@
|
||||
#define MEMORY_SLOT_PROXIMITY MPX
|
||||
#define MEMORY_SLOT_ENABLED MES
|
||||
#define MEMORY_SLOT_INSERT_EVENT MINS
|
||||
#define MEMORY_SLOT_REMOVE_EVENT MRMV
|
||||
#define MEMORY_SLOT_EJECT MEJ
|
||||
#define MEMORY_SLOT_SLECTOR MSEL
|
||||
#define MEMORY_SLOT_OST_EVENT MOEV
|
||||
#define MEMORY_SLOT_OST_STATUS MOSC
|
||||
@ -51,6 +53,7 @@
|
||||
#define MEMORY_SLOT_CRS_METHOD MCRS
|
||||
#define MEMORY_SLOT_OST_METHOD MOST
|
||||
#define MEMORY_SLOT_PROXIMITY_METHOD MPXM
|
||||
#define MEMORY_SLOT_EJECT_METHOD MEJ0
|
||||
#define MEMORY_SLOT_NOTIFY_METHOD MTFY
|
||||
#define MEMORY_SLOT_SCAN_METHOD MSCN
|
||||
|
||||
|
@ -266,6 +266,7 @@ int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
|
||||
void qdev_init_nofail(DeviceState *dev);
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version);
|
||||
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
|
||||
void qdev_unplug(DeviceState *dev, Error **errp);
|
||||
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp);
|
||||
|
@ -62,6 +62,7 @@ typedef struct VirtioBusClass {
|
||||
* This is called by virtio-bus just before the device is unplugged.
|
||||
*/
|
||||
void (*device_unplugged)(DeviceState *d);
|
||||
int (*query_nvectors)(DeviceState *d);
|
||||
/*
|
||||
* Does the transport have variable vring alignment?
|
||||
* (ie can it ever call virtio_queue_set_align()?)
|
||||
|
@ -68,6 +68,7 @@ typedef struct VirtIONet {
|
||||
uint32_t has_vnet_hdr;
|
||||
size_t host_hdr_len;
|
||||
size_t guest_hdr_len;
|
||||
uint32_t host_features;
|
||||
uint8_t has_ufo;
|
||||
int mergeable_rx_bufs;
|
||||
uint8_t promisc;
|
||||
@ -137,7 +138,6 @@ typedef struct VirtIONet {
|
||||
DEFINE_PROP_INT32("x-txburst", _state, _field.txburst, TX_BURST), \
|
||||
DEFINE_PROP_STRING("tx", _state, _field.tx)
|
||||
|
||||
void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features);
|
||||
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
|
||||
const char *type);
|
||||
|
||||
|
@ -98,6 +98,7 @@ typedef struct VirtIOSCSI {
|
||||
bool dataplane_fenced;
|
||||
Error *blocker;
|
||||
Notifier migration_state_notifier;
|
||||
uint32_t host_features;
|
||||
} VirtIOSCSI;
|
||||
|
||||
typedef struct VirtIOSCSIReq {
|
||||
|
@ -84,6 +84,7 @@ struct VirtIODevice
|
||||
VMChangeStateEntry *vmstate;
|
||||
char *bus_name;
|
||||
uint8_t device_endian;
|
||||
QLIST_HEAD(, VirtQueue) *vector_queues;
|
||||
};
|
||||
|
||||
typedef struct VirtioDeviceClass {
|
||||
@ -218,6 +219,8 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
|
||||
bool set_handler);
|
||||
void virtio_queue_notify_vq(VirtQueue *vq);
|
||||
void virtio_irq(VirtQueue *vq);
|
||||
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
|
||||
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
|
||||
|
||||
static inline void virtio_add_feature(uint32_t *features, unsigned int fbit)
|
||||
{
|
||||
|
25
monitor.c
25
monitor.c
@ -4471,11 +4471,12 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
len = strlen(str);
|
||||
readline_set_completion_index(rs, len);
|
||||
if (nb_args == 2) {
|
||||
NetClientState *ncs[255];
|
||||
NetClientState *ncs[MAX_QUEUE_NUM];
|
||||
int count, i;
|
||||
count = qemu_find_net_clients_except(NULL, ncs,
|
||||
NET_CLIENT_OPTIONS_KIND_NONE, 255);
|
||||
for (i = 0; i < count; i++) {
|
||||
NET_CLIENT_OPTIONS_KIND_NONE,
|
||||
MAX_QUEUE_NUM);
|
||||
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
||||
const char *name = ncs[i]->name;
|
||||
if (!strncmp(str, name, len)) {
|
||||
readline_add_completion(rs, name);
|
||||
@ -4490,7 +4491,7 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
{
|
||||
int len, count, i;
|
||||
NetClientState *ncs[255];
|
||||
NetClientState *ncs[MAX_QUEUE_NUM];
|
||||
|
||||
if (nb_args != 2) {
|
||||
return;
|
||||
@ -4499,8 +4500,8 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
len = strlen(str);
|
||||
readline_set_completion_index(rs, len);
|
||||
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
255);
|
||||
for (i = 0; i < count; i++) {
|
||||
MAX_QUEUE_NUM);
|
||||
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
||||
QemuOpts *opts;
|
||||
const char *name = ncs[i]->name;
|
||||
if (strncmp(str, name, len)) {
|
||||
@ -4583,15 +4584,16 @@ void host_net_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
|
||||
void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
{
|
||||
NetClientState *ncs[255];
|
||||
NetClientState *ncs[MAX_QUEUE_NUM];
|
||||
int count, i, len;
|
||||
|
||||
len = strlen(str);
|
||||
readline_set_completion_index(rs, len);
|
||||
if (nb_args == 2) {
|
||||
count = qemu_find_net_clients_except(NULL, ncs,
|
||||
NET_CLIENT_OPTIONS_KIND_NONE, 255);
|
||||
for (i = 0; i < count; i++) {
|
||||
NET_CLIENT_OPTIONS_KIND_NONE,
|
||||
MAX_QUEUE_NUM);
|
||||
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
||||
int id;
|
||||
char name[16];
|
||||
|
||||
@ -4606,8 +4608,9 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||
return;
|
||||
} else if (nb_args == 3) {
|
||||
count = qemu_find_net_clients_except(NULL, ncs,
|
||||
NET_CLIENT_OPTIONS_KIND_NIC, 255);
|
||||
for (i = 0; i < count; i++) {
|
||||
NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
MAX_QUEUE_NUM);
|
||||
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
||||
int id;
|
||||
const char *name;
|
||||
|
||||
|
@ -330,3 +330,17 @@
|
||||
##
|
||||
{ 'event': 'VSERPORT_CHANGE',
|
||||
'data': { 'id': 'str', 'open': 'bool' } }
|
||||
|
||||
##
|
||||
# @MEM_UNPLUG_ERROR
|
||||
#
|
||||
# Emitted when memory hot unplug error occurs.
|
||||
#
|
||||
# @device: device name
|
||||
#
|
||||
# @msg: Informative message
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'event': 'MEM_UNPLUG_ERROR',
|
||||
'data': { 'device': 'str', 'msg': 'str' } }
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -17,7 +17,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "libqtest.h"
|
||||
#include "qemu/compiler.h"
|
||||
#include "hw/i386/acpi-defs.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/i386/smbios.h"
|
||||
#include "qemu/bitmap.h"
|
||||
|
||||
|
@ -1562,6 +1562,7 @@ vfio_put_base_device(int fd) "close vdev->fd=%d"
|
||||
|
||||
#hw/acpi/memory_hotplug.c
|
||||
mhp_acpi_invalid_slot_selected(uint32_t slot) "0x%"PRIx32
|
||||
mhp_acpi_ejecting_invalid_slot(uint32_t slot) "0x%"PRIx32
|
||||
mhp_acpi_read_addr_lo(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr lo: 0x%"PRIx32
|
||||
mhp_acpi_read_addr_hi(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr hi: 0x%"PRIx32
|
||||
mhp_acpi_read_size_lo(uint32_t slot, uint32_t size) "slot[0x%"PRIx32"] size lo: 0x%"PRIx32
|
||||
@ -1572,6 +1573,9 @@ mhp_acpi_write_slot(uint32_t slot) "set active slot: 0x%"PRIx32
|
||||
mhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "slot[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
|
||||
mhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "slot[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
|
||||
mhp_acpi_clear_insert_evt(uint32_t slot) "slot[0x%"PRIx32"] clear insert event"
|
||||
mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event"
|
||||
mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted"
|
||||
mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed"
|
||||
|
||||
# hw/i386/pc.c
|
||||
mhp_pc_dimm_assigned_slot(int slot) "0x%d"
|
||||
|
Loading…
x
Reference in New Issue
Block a user