summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/aml-build.c26
-rw-r--r--hw/acpi/cpu.c7
-rw-r--r--hw/arm/virt-acpi-build.c19
-rw-r--r--hw/arm/virt.c123
-rw-r--r--hw/block/nvme.c26
-rw-r--r--hw/block/nvme.h1
-rw-r--r--hw/core/machine.c162
-rw-r--r--hw/display/cg3.c41
-rw-r--r--hw/display/sm501.c27
-rw-r--r--hw/display/tcx.c68
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/display/virtio-gpu-3d.c16
-rw-r--r--hw/display/virtio-gpu.c18
-rw-r--r--hw/i386/acpi-build.c15
-rw-r--r--hw/i386/pc.c54
-rw-r--r--hw/i386/pc_piix.c2
-rw-r--r--hw/i386/pc_q35.c2
-rw-r--r--hw/input/virtio-input-hid.c6
-rw-r--r--hw/intc/xics_kvm.c13
-rw-r--r--hw/ppc/mac_newworld.c18
-rw-r--r--hw/ppc/mac_oldworld.c18
-rw-r--r--hw/ppc/pnv.c2
-rw-r--r--hw/ppc/spapr.c63
-rw-r--r--hw/ppc/spapr_cpu_core.c21
-rw-r--r--hw/ppc/spapr_hcall.c18
-rw-r--r--hw/usb/dev-hub.c1
-rw-r--r--hw/usb/dev-serial.c24
-rw-r--r--hw/usb/hcd-xhci.c9
-rw-r--r--hw/usb/redirect.c13
29 files changed, 580 insertions, 235 deletions
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index c6f2032dec..be496c817c 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -24,6 +24,7 @@
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
#include "qemu/bitops.h"
+#include "sysemu/numa.h"
static GArray *build_alloc_array(void)
{
@@ -1609,3 +1610,28 @@ void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
numamem->base_addr = cpu_to_le64(base);
numamem->range_length = cpu_to_le64(len);
}
+
+/*
+ * ACPI spec 5.2.17 System Locality Distance Information Table
+ * (Revision 2.0 or later)
+ */
+void build_slit(GArray *table_data, BIOSLinker *linker)
+{
+ int slit_start, i, j;
+ slit_start = table_data->len;
+
+ acpi_data_push(table_data, sizeof(AcpiTableHeader));
+
+ build_append_int_noprefix(table_data, nb_numa_nodes, 8);
+ for (i = 0; i < nb_numa_nodes; i++) {
+ for (j = 0; j < nb_numa_nodes; j++) {
+ assert(numa_info[i].distance[j]);
+ build_append_int_noprefix(table_data, numa_info[i].distance[j], 1);
+ }
+ }
+
+ build_header(linker, table_data,
+ (void *)(table_data->data + slit_start),
+ "SLIT",
+ table_data->len - slit_start, 1, NULL, NULL);
+}
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 8c719d3f9d..a233fe17cf 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -503,7 +503,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
/* build Processor object for each processor */
for (i = 0; i < arch_ids->len; i++) {
- int j;
Aml *dev;
Aml *uid = aml_int(i);
GArray *madt_buf = g_array_new(0, 1, 1);
@@ -557,9 +556,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
* as a result _PXM is required for all CPUs which might
* be hot-plugged. For simplicity, add it for all CPUs.
*/
- j = numa_get_node_for_cpu(i);
- if (j < nb_numa_nodes) {
- aml_append(dev, aml_name_decl("_PXM", aml_int(j)));
+ if (arch_ids->cpus[i].props.has_node_id) {
+ aml_append(dev, aml_name_decl("_PXM",
+ aml_int(arch_ids->cpus[i].props.node_id)));
}
aml_append(cpus_dev, dev);
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0835e59bb2..ce7499c9ca 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -486,30 +486,25 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiSystemResourceAffinityTable *srat;
AcpiSratProcessorGiccAffinity *core;
AcpiSratMemoryAffinity *numamem;
- int i, j, srat_start;
+ int i, srat_start;
uint64_t mem_base;
- uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t));
-
- for (i = 0; i < vms->smp_cpus; i++) {
- j = numa_get_node_for_cpu(i);
- if (j < nb_numa_nodes) {
- cpu_node[i] = j;
- }
- }
+ MachineClass *mc = MACHINE_GET_CLASS(vms);
+ const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms));
srat_start = table_data->len;
srat = acpi_data_push(table_data, sizeof(*srat));
srat->reserved1 = cpu_to_le32(1);
- for (i = 0; i < vms->smp_cpus; ++i) {
+ for (i = 0; i < cpu_list->len; ++i) {
+ int node_id = cpu_list->cpus[i].props.has_node_id ?
+ cpu_list->cpus[i].props.node_id : 0;
core = acpi_data_push(table_data, sizeof(*core));
core->type = ACPI_SRAT_PROCESSOR_GICC;
core->length = sizeof(*core);
- core->proximity = cpu_to_le32(cpu_node[i]);
+ core->proximity = cpu_to_le32(node_id);
core->acpi_processor_uid = cpu_to_le32(i);
core->flags = cpu_to_le32(1);
}
- g_free(cpu_node);
mem_base = vms->memmap[VIRT_MEM].base;
for (i = 0; i < nb_numa_nodes; ++i) {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 5f62a0321e..c7c8159dfd 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -338,7 +338,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
{
int cpu;
int addr_cells = 1;
- unsigned int i;
+ const MachineState *ms = MACHINE(vms);
/*
* From Documentation/devicetree/bindings/arm/cpus.txt
@@ -369,6 +369,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) {
char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
+ CPUState *cs = CPU(armcpu);
qemu_fdt_add_subnode(vms->fdt, nodename);
qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "cpu");
@@ -389,9 +390,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
armcpu->mp_affinity);
}
- i = numa_get_node_for_cpu(cpu);
- if (i < nb_numa_nodes) {
- qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", i);
+ if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
+ qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id",
+ ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
}
g_free(nodename);
@@ -1194,10 +1195,35 @@ void virt_machine_done(Notifier *notifier, void *data)
virt_build_smbios(vms);
}
+static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
+{
+ uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+
+ if (!vmc->disallow_affinity_adjustment) {
+ /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the
+ * GIC's target-list limitations. 32-bit KVM hosts currently
+ * always create clusters of 4 CPUs, but that is expected to
+ * change when they gain support for gicv3. When KVM is enabled
+ * it will override the changes we make here, therefore our
+ * purposes are to make TCG consistent (with 64-bit KVM hosts)
+ * and to improve SGI efficiency.
+ */
+ if (vms->gic_version == 3) {
+ clustersz = GICV3_TARGETLIST_BITS;
+ } else {
+ clustersz = GIC_TARGETLIST_BITS;
+ }
+ }
+ return arm_cpu_mp_affinity(idx, clustersz);
+}
+
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ const CPUArchIdList *possible_cpus;
qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *secure_sysmem = NULL;
@@ -1210,7 +1236,6 @@ static void machvirt_init(MachineState *machine)
CPUClass *cc;
Error *err = NULL;
bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
- uint8_t clustersz;
if (!cpu_model) {
cpu_model = "cortex-a15";
@@ -1263,10 +1288,8 @@ static void machvirt_init(MachineState *machine)
*/
if (vms->gic_version == 3) {
virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / 0x20000;
- clustersz = GICV3_TARGETLIST_BITS;
} else {
virt_max_cpus = GIC_NCPU;
- clustersz = GIC_TARGETLIST_BITS;
}
if (max_cpus > virt_max_cpus) {
@@ -1324,21 +1347,35 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
- for (n = 0; n < smp_cpus; n++) {
- Object *cpuobj = object_new(typename);
- if (!vmc->disallow_affinity_adjustment) {
- /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the
- * GIC's target-list limitations. 32-bit KVM hosts currently
- * always create clusters of 4 CPUs, but that is expected to
- * change when they gain support for gicv3. When KVM is enabled
- * it will override the changes we make here, therefore our
- * purposes are to make TCG consistent (with 64-bit KVM hosts)
- * and to improve SGI efficiency.
- */
- uint8_t aff1 = n / clustersz;
- uint8_t aff0 = n % clustersz;
- object_property_set_int(cpuobj, (aff1 << ARM_AFF1_SHIFT) | aff0,
- "mp-affinity", NULL);
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ for (n = 0; n < possible_cpus->len; n++) {
+ Object *cpuobj;
+ CPUState *cs;
+ int node_id;
+
+ if (n >= smp_cpus) {
+ break;
+ }
+
+ cpuobj = object_new(typename);
+ object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
+ "mp-affinity", NULL);
+
+ cs = CPU(cpuobj);
+ cs->cpu_index = n;
+
+ node_id = possible_cpus->cpus[cs->cpu_index].props.node_id;
+ if (!possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
+ /* by default CPUState::numa_node was 0 if it's not set via CLI
+ * keep it this way for now but in future we probably should
+ * refuse to start up with incomplete numa mapping */
+ node_id = 0;
+ }
+ if (cs->numa_node == CPU_UNSET_NUMA_NODE_ID) {
+ cs->numa_node = node_id;
+ } else {
+ /* CPU isn't device_add compatible yet, this shouldn't happen */
+ error_setg(&error_abort, "user set node-id not implemented");
}
if (!vms->secure) {
@@ -1518,6 +1555,46 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp)
}
}
+static CpuInstanceProperties
+virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+
+ assert(cpu_index < possible_cpus->len);
+ return possible_cpus->cpus[cpu_index].props;
+}
+
+static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
+{
+ int n;
+ VirtMachineState *vms = VIRT_MACHINE(ms);
+
+ if (ms->possible_cpus) {
+ assert(ms->possible_cpus->len == max_cpus);
+ return ms->possible_cpus;
+ }
+
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
+ sizeof(CPUArchId) * max_cpus);
+ ms->possible_cpus->len = max_cpus;
+ for (n = 0; n < ms->possible_cpus->len; n++) {
+ ms->possible_cpus->cpus[n].arch_id =
+ virt_cpu_mp_affinity(vms, n);
+ ms->possible_cpus->cpus[n].props.has_thread_id = true;
+ ms->possible_cpus->cpus[n].props.thread_id = n;
+
+ /* default distribution of CPUs over NUMA nodes */
+ if (nb_numa_nodes) {
+ /* preset values but do not enable them i.e. 'has_node_id = false',
+ * numa init code will enable them later if manual mapping wasn't
+ * present on CLI */
+ ms->possible_cpus->cpus[n].props.node_id = n % nb_numa_nodes;
+ }
+ }
+ return ms->possible_cpus;
+}
+
static void virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1534,6 +1611,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->pci_allow_0_address = true;
/* We know we will never create a pre-ARMv7 CPU which needs 1K pages */
mc->minimum_page_bits = 12;
+ mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
+ mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
}
static const TypeInfo virt_machine_info = {
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index ae303d44e5..7428db9f0c 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -227,6 +227,29 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
return NVME_NO_COMPLETE;
}
+static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
+ NvmeRequest *req)
+{
+ NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
+ const uint8_t lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
+ const uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
+ uint64_t slba = le64_to_cpu(rw->slba);
+ uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
+ uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
+ uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
+
+ if (slba + nlb > ns->id_ns.nsze) {
+ return NVME_LBA_RANGE | NVME_DNR;
+ }
+
+ req->has_sg = false;
+ block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
+ BLOCK_ACCT_WRITE);
+ req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, aio_slba, aio_nlb,
+ BDRV_REQ_MAY_UNMAP, nvme_rw_cb, req);
+ return NVME_NO_COMPLETE;
+}
+
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
NvmeRequest *req)
{
@@ -279,6 +302,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
switch (cmd->opcode) {
case NVME_CMD_FLUSH:
return nvme_flush(n, ns, cmd, req);
+ case NVME_CMD_WRITE_ZEROS:
+ return nvme_write_zeros(n, ns, cmd, req);
case NVME_CMD_WRITE:
case NVME_CMD_READ:
return nvme_rw(n, ns, cmd, req);
@@ -895,6 +920,7 @@ static int nvme_init(PCIDevice *pci_dev)
id->sqes = (0x6 << 4) | 0x6;
id->cqes = (0x4 << 4) | 0x4;
id->nn = cpu_to_le32(n->num_namespaces);
+ id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS);
id->psd[0].mp = cpu_to_le16(0x9c4);
id->psd[0].enlat = cpu_to_le32(0x10);
id->psd[0].exlat = cpu_to_le32(0x4);
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 8fb0c10756..a0d15649f9 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -179,6 +179,7 @@ enum NvmeIoCommands {
NVME_CMD_READ = 0x02,
NVME_CMD_WRITE_UNCOR = 0x04,
NVME_CMD_COMPARE = 0x05,
+ NVME_CMD_WRITE_ZEROS = 0x08,
NVME_CMD_DSM = 0x09,
};
diff --git a/hw/core/machine.c b/hw/core/machine.c
index ada9eea483..fd6a436064 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -17,8 +17,10 @@
#include "qapi/visitor.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
+#include "sysemu/numa.h"
#include "qemu/error-report.h"
#include "qemu/cutils.h"
+#include "sysemu/numa.h"
static char *machine_get_accel(Object *obj, Error **errp)
{
@@ -388,6 +390,102 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
return head;
}
+/**
+ * machine_set_cpu_numa_node:
+ * @machine: machine object to modify
+ * @props: specifies which cpu objects to assign to
+ * numa node specified by @props.node_id
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Associate NUMA node specified by @props.node_id with cpu slots that
+ * match socket/core/thread-ids specified by @props. It's recommended to use
+ * query-hotpluggable-cpus.props values to specify affected cpu slots,
+ * which would lead to exact 1:1 mapping of cpu slots to NUMA node.
+ *
+ * However for CLI convenience it's possible to pass in subset of properties,
+ * which would affect all cpu slots that match it.
+ * Ex for pc machine:
+ * -smp 4,cores=2,sockets=2 -numa node,nodeid=0 -numa node,nodeid=1 \
+ * -numa cpu,node-id=0,socket_id=0 \
+ * -numa cpu,node-id=1,socket_id=1
+ * will assign all child cores of socket 0 to node 0 and
+ * of socket 1 to node 1.
+ *
+ * On attempt of reassigning (already assigned) cpu slot to another NUMA node,
+ * return error.
+ * Empty subset is disallowed and function will return with error in this case.
+ */
+void machine_set_cpu_numa_node(MachineState *machine,
+ const CpuInstanceProperties *props, Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ bool match = false;
+ int i;
+
+ if (!mc->possible_cpu_arch_ids) {
+ error_setg(errp, "mapping of CPUs to NUMA node is not supported");
+ return;
+ }
+
+ /* disabling node mapping is not supported, forbid it */
+ assert(props->has_node_id);
+
+ /* force board to initialize possible_cpus if it hasn't been done yet */
+ mc->possible_cpu_arch_ids(machine);
+
+ for (i = 0; i < machine->possible_cpus->len; i++) {
+ CPUArchId *slot = &machine->possible_cpus->cpus[i];
+
+ /* reject unsupported by board properties */
+ if (props->has_thread_id && !slot->props.has_thread_id) {
+ error_setg(errp, "thread-id is not supported");
+ return;
+ }
+
+ if (props->has_core_id && !slot->props.has_core_id) {
+ error_setg(errp, "core-id is not supported");
+ return;
+ }
+
+ if (props->has_socket_id && !slot->props.has_socket_id) {
+ error_setg(errp, "socket-id is not supported");
+ return;
+ }
+
+ /* skip slots with explicit mismatch */
+ if (props->has_thread_id && props->thread_id != slot->props.thread_id) {
+ continue;
+ }
+
+ if (props->has_core_id && props->core_id != slot->props.core_id) {
+ continue;
+ }
+
+ if (props->has_socket_id && props->socket_id != slot->props.socket_id) {
+ continue;
+ }
+
+ /* reject assignment if slot is already assigned, for compatibility
+ * of legacy cpu_index mapping with SPAPR core based mapping do not
+ * error out if cpu thread and matched core have the same node-id */
+ if (slot->props.has_node_id &&
+ slot->props.node_id != props->node_id) {
+ error_setg(errp, "CPU is already assigned to node-id: %" PRId64,
+ slot->props.node_id);
+ return;
+ }
+
+ /* assign slot to node as it's matched '-numa cpu' key */
+ match = true;
+ slot->props.node_id = props->node_id;
+ slot->props.has_node_id = props->has_node_id;
+ }
+
+ if (!match) {
+ error_setg(errp, "no match found");
+ }
+}
+
static void machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -400,6 +498,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
* On Linux, each node's border has to be 8MB aligned
*/
mc->numa_mem_align_shift = 23;
+ mc->numa_auto_assign_ram = numa_default_auto_assign_ram;
object_class_property_add_str(oc, "accel",
machine_get_accel, machine_set_accel, &error_abort);
@@ -580,6 +679,69 @@ bool machine_mem_merge(MachineState *machine)
return machine->mem_merge;
}
+static char *cpu_slot_to_string(const CPUArchId *cpu)
+{
+ GString *s = g_string_new(NULL);
+ if (cpu->props.has_socket_id) {
+ g_string_append_printf(s, "socket-id: %"PRId64, cpu->props.socket_id);
+ }
+ if (cpu->props.has_core_id) {
+ if (s->len) {
+ g_string_append_printf(s, ", ");
+ }
+ g_string_append_printf(s, "core-id: %"PRId64, cpu->props.core_id);
+ }
+ if (cpu->props.has_thread_id) {
+ if (s->len) {
+ g_string_append_printf(s, ", ");
+ }
+ g_string_append_printf(s, "thread-id: %"PRId64, cpu->props.thread_id);
+ }
+ return g_string_free(s, false);
+}
+
+static void machine_numa_validate(MachineState *machine)
+{
+ int i;
+ GString *s = g_string_new(NULL);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine);
+
+ assert(nb_numa_nodes);
+ for (i = 0; i < possible_cpus->len; i++) {
+ const CPUArchId *cpu_slot = &possible_cpus->cpus[i];
+
+ /* at this point numa mappings are initilized by CLI options
+ * or with default mappings so it's sufficient to list
+ * all not yet mapped CPUs here */
+ /* TODO: make it hard error in future */
+ if (!cpu_slot->props.has_node_id) {
+ char *cpu_str = cpu_slot_to_string(cpu_slot);
+ g_string_append_printf(s, "%sCPU %d [%s]", s->len ? ", " : "", i,
+ cpu_str);
+ g_free(cpu_str);
+ }
+ }
+ if (s->len) {
+ error_report("warning: CPU(s) not present in any NUMA nodes: %s",
+ s->str);
+ error_report("warning: All CPU(s) up to maxcpus should be described "
+ "in NUMA config, ability to start up with partial NUMA "
+ "mappings is obsoleted and will be removed in future");
+ }
+ g_string_free(s, true);
+}
+
+void machine_run_board_init(MachineState *machine)
+{
+ MachineClass *machine_class = MACHINE_GET_CLASS(machine);
+
+ if (nb_numa_nodes) {
+ machine_numa_validate(machine);
+ }
+ machine_class->init(machine);
+}
+
static void machine_class_finalize(ObjectClass *klass, void *data)
{
MachineClass *mc = MACHINE_CLASS(klass);
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 7ef8a96496..1de15a1d34 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -94,7 +94,8 @@ static void cg3_update_display(void *opaque)
uint32_t dval;
int x, y, y_start;
unsigned int width, height;
- ram_addr_t page, page_min, page_max;
+ ram_addr_t page;
+ DirtyBitmapSnapshot *snap = NULL;
if (surface_bits_per_pixel(surface) != 32) {
return;
@@ -103,29 +104,32 @@ static void cg3_update_display(void *opaque)
height = s->height;
y_start = -1;
- page_min = -1;
- page_max = 0;
- page = 0;
pix = memory_region_get_ram_ptr(&s->vram_mem);
data = (uint32_t *)surface_data(surface);
- memory_region_sync_dirty_bitmap(&s->vram_mem);
+ if (!s->full_update) {
+ memory_region_sync_dirty_bitmap(&s->vram_mem);
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram_mem, 0x0,
+ memory_region_size(&s->vram_mem),
+ DIRTY_MEMORY_VGA);
+ }
+
for (y = 0; y < height; y++) {
- int update = s->full_update;
+ int update;
page = (ram_addr_t)y * width;
- update |= memory_region_get_dirty(&s->vram_mem, page, width,
- DIRTY_MEMORY_VGA);
+
+ if (s->full_update) {
+ update = 1;
+ } else {
+ update = memory_region_snapshot_get_dirty(&s->vram_mem, snap, page,
+ width);
+ }
+
if (update) {
if (y_start < 0) {
y_start = y;
}
- if (page < page_min) {
- page_min = page;
- }
- if (page > page_max) {
- page_max = page;
- }
for (x = 0; x < width; x++) {
dval = *pix++;
@@ -134,7 +138,7 @@ static void cg3_update_display(void *opaque)
}
} else {
if (y_start >= 0) {
- dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
y_start = -1;
}
pix += width;
@@ -143,17 +147,14 @@ static void cg3_update_display(void *opaque)
}
s->full_update = 0;
if (y_start >= 0) {
- dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
- }
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram_mem,
- page_min, page_max - page_min, DIRTY_MEMORY_VGA);
+ dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
}
/* vsync interrupt? */
if (s->regs[0] & CG3_CR_ENABLE_INTS) {
s->regs[1] |= CG3_SR_PENDING_INT;
qemu_irq_raise(s->irq);
}
+ g_free(snap);
}
static void cg3_invalidate_display(void *opaque)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 2094adbc9c..9d254ef2e1 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1414,6 +1414,7 @@ static void sm501_update_display(void *opaque)
{
SM501State *s = (SM501State *)opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
+ DirtyBitmapSnapshot *snap;
int y, c_x = 0, c_y = 0;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int width = get_width(s, crt);
@@ -1425,9 +1426,7 @@ static void sm501_update_display(void *opaque)
draw_hwc_line_func *draw_hwc_line = NULL;
int full_update = 0;
int y_start = -1;
- ram_addr_t page_min = ~0l;
- ram_addr_t page_max = 0l;
- ram_addr_t offset;
+ ram_addr_t offset = 0;
uint32_t *palette;
uint8_t hwc_palette[3 * 3];
uint8_t *hwc_src = NULL;
@@ -1479,17 +1478,17 @@ static void sm501_update_display(void *opaque)
/* draw each line according to conditions */
memory_region_sync_dirty_bitmap(&s->local_mem_region);
+ snap = memory_region_snapshot_and_clear_dirty(&s->local_mem_region,
+ offset, width * height * src_bpp, DIRTY_MEMORY_VGA);
for (y = 0, offset = 0; y < height; y++, offset += width * src_bpp) {
int update, update_hwc;
- ram_addr_t page0 = offset;
- ram_addr_t page1 = offset + width * src_bpp - 1;
/* check if hardware cursor is enabled and we're within its range */
update_hwc = draw_hwc_line && c_y <= y && y < c_y + SM501_HWC_HEIGHT;
update = full_update || update_hwc;
/* check dirty flags for each line */
- update |= memory_region_get_dirty(&s->local_mem_region, page0,
- page1 - page0, DIRTY_MEMORY_VGA);
+ update |= memory_region_snapshot_get_dirty(&s->local_mem_region, snap,
+ offset, width * src_bpp);
/* draw line and change status */
if (update) {
@@ -1507,12 +1506,6 @@ static void sm501_update_display(void *opaque)
if (y_start < 0) {
y_start = y;
}
- if (page0 < page_min) {
- page_min = page0;
- }
- if (page1 > page_max) {
- page_max = page1;
- }
} else {
if (y_start >= 0) {
/* flush to display */
@@ -1521,18 +1514,12 @@ static void sm501_update_display(void *opaque)
}
}
}
+ g_free(snap);
/* complete flush to display */
if (y_start >= 0) {
dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
}
-
- /* clear dirty flags */
- if (page_min != ~0l) {
- memory_region_reset_dirty(&s->local_mem_region,
- page_min, page_max + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
}
static const GraphicHwOps sm501_ops = {
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 0e66dcd055..6593c1d6af 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -104,36 +104,23 @@ static void tcx_set_dirty(TCXState *s, ram_addr_t addr, int len)
}
}
-static int tcx_check_dirty(TCXState *s, ram_addr_t addr, int len)
+static int tcx_check_dirty(TCXState *s, DirtyBitmapSnapshot *snap,
+ ram_addr_t addr, int len)
{
int ret;
- ret = memory_region_get_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA);
+ ret = memory_region_snapshot_get_dirty(&s->vram_mem, snap, addr, len);
if (s->depth == 24) {
- ret |= memory_region_get_dirty(&s->vram_mem,
- s->vram24_offset + addr * 4, len * 4,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem,
- s->cplane_offset + addr * 4, len * 4,
- DIRTY_MEMORY_VGA);
+ ret |= memory_region_snapshot_get_dirty(&s->vram_mem, snap,
+ s->vram24_offset + addr * 4, len * 4);
+ ret |= memory_region_snapshot_get_dirty(&s->vram_mem, snap,
+ s->cplane_offset + addr * 4, len * 4);
}
return ret;
}
-static void tcx_reset_dirty(TCXState *s, ram_addr_t addr, int len)
-{
- memory_region_reset_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA);
-
- if (s->depth == 24) {
- memory_region_reset_dirty(&s->vram_mem, s->vram24_offset + addr * 4,
- len * 4, DIRTY_MEMORY_VGA);
- memory_region_reset_dirty(&s->vram_mem, s->cplane_offset + addr * 4,
- len * 4, DIRTY_MEMORY_VGA);
- }
-}
-
static void update_palette_entries(TCXState *s, int start, int end)
{
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -233,7 +220,8 @@ static void tcx_update_display(void *opaque)
{
TCXState *ts = opaque;
DisplaySurface *surface = qemu_console_surface(ts->con);
- ram_addr_t page, page_min, page_max;
+ ram_addr_t page;
+ DirtyBitmapSnapshot *snap = NULL;
int y, y_start, dd, ds;
uint8_t *d, *s;
@@ -243,22 +231,20 @@ static void tcx_update_display(void *opaque)
page = 0;
y_start = -1;
- page_min = -1;
- page_max = 0;
d = surface_data(surface);
s = ts->vram;
dd = surface_stride(surface);
ds = 1024;
memory_region_sync_dirty_bitmap(&ts->vram_mem);
+ snap = memory_region_snapshot_and_clear_dirty(&ts->vram_mem, 0x0,
+ memory_region_size(&ts->vram_mem),
+ DIRTY_MEMORY_VGA);
+
for (y = 0; y < ts->height; y++, page += ds) {
- if (tcx_check_dirty(ts, page, ds)) {
+ if (tcx_check_dirty(ts, snap, page, ds)) {
if (y_start < 0)
y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
tcx_draw_line32(ts, d, s, ts->width);
if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) {
@@ -280,17 +266,15 @@ static void tcx_update_display(void *opaque)
dpy_gfx_update(ts->con, 0, y_start,
ts->width, y - y_start);
}
- /* reset modified pages */
- if (page_max >= page_min) {
- tcx_reset_dirty(ts, page_min, page_max - page_min);
- }
+ g_free(snap);
}
static void tcx24_update_display(void *opaque)
{
TCXState *ts = opaque;
DisplaySurface *surface = qemu_console_surface(ts->con);
- ram_addr_t page, page_min, page_max;
+ ram_addr_t page;
+ DirtyBitmapSnapshot *snap = NULL;
int y, y_start, dd, ds;
uint8_t *d, *s;
uint32_t *cptr, *s24;
@@ -301,8 +285,6 @@ static void tcx24_update_display(void *opaque)
page = 0;
y_start = -1;
- page_min = -1;
- page_max = 0;
d = surface_data(surface);
s = ts->vram;
s24 = ts->vram24;
@@ -311,14 +293,15 @@ static void tcx24_update_display(void *opaque)
ds = 1024;
memory_region_sync_dirty_bitmap(&ts->vram_mem);
+ snap = memory_region_snapshot_and_clear_dirty(&ts->vram_mem, 0x0,
+ memory_region_size(&ts->vram_mem),
+ DIRTY_MEMORY_VGA);
+
for (y = 0; y < ts->height; y++, page += ds) {
- if (tcx_check_dirty(ts, page, ds)) {
+ if (tcx_check_dirty(ts, snap, page, ds)) {
if (y_start < 0)
y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
+
tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) {
tcx_draw_cursor32(ts, d, y, ts->width);
@@ -341,10 +324,7 @@ static void tcx24_update_display(void *opaque)
dpy_gfx_update(ts->con, 0, y_start,
ts->width, y - y_start);
}
- /* reset modified pages */
- if (page_max >= page_min) {
- tcx_reset_dirty(ts, page_min, page_max - page_min);
- }
+ g_free(snap);
}
static void tcx_invalidate_display(void *opaque)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b2516c8d21..dcc95f88e2 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1630,7 +1630,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (!full_update) {
vga_sync_dirty_bitmap(s);
snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
- bwidth * height,
+ line_offset * height,
DIRTY_MEMORY_VGA);
}
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index f49b7fe8cd..8c106a662d 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -600,6 +600,22 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
}
}
+void virtio_gpu_gl_block(void *opaque, bool block)
+{
+ VirtIOGPU *g = opaque;
+
+ if (block) {
+ g->renderer_blocked++;
+ } else {
+ g->renderer_blocked--;
+ }
+ assert(g->renderer_blocked >= 0);
+
+ if (g->renderer_blocked == 0) {
+ virtio_gpu_process_cmdq(g);
+ }
+}
+
int virtio_gpu_virgl_init(VirtIOGPU *g)
{
int ret;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index e1056f34df..cfb5dfa336 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -929,28 +929,14 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
return 0;
}
-static void virtio_gpu_gl_block(void *opaque, bool block)
-{
- VirtIOGPU *g = opaque;
-
- if (block) {
- g->renderer_blocked++;
- } else {
- g->renderer_blocked--;
- }
- assert(g->renderer_blocked >= 0);
-
- if (g->renderer_blocked == 0) {
- virtio_gpu_process_cmdq(g);
- }
-}
-
const GraphicHwOps virtio_gpu_ops = {
.invalidate = virtio_gpu_invalidate_display,
.gfx_update = virtio_gpu_update_display,
.text_update = virtio_gpu_text_update,
.ui_info = virtio_gpu_ui_info,
+#ifdef CONFIG_VIRGL
.gl_block = virtio_gpu_gl_block,
+#endif
};
static const VMStateDescription vmstate_virtio_gpu_scanout = {
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 1d8c645ed3..cc0418f327 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2335,7 +2335,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
srat->reserved1 = cpu_to_le32(1);
for (i = 0; i < apic_ids->len; i++) {
- int j = numa_get_node_for_cpu(i);
+ int node_id = apic_ids->cpus[i].props.has_node_id ?
+ apic_ids->cpus[i].props.node_id : 0;
uint32_t apic_id = apic_ids->cpus[i].arch_id;
if (apic_id < 255) {
@@ -2345,9 +2346,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
core->type = ACPI_SRAT_PROCESSOR_APIC;
core->length = sizeof(*core);
core->local_apic_id = apic_id;
- if (j < nb_numa_nodes) {
- core->proximity_lo = j;
- }
+ core->proximity_lo = node_id;
memset(core->proximity_hi, 0, 3);
core->local_sapic_eid = 0;
core->flags = cpu_to_le32(1);
@@ -2358,9 +2357,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
core->type = ACPI_SRAT_PROCESSOR_x2APIC;
core->length = sizeof(*core);
core->x2apic_id = cpu_to_le32(apic_id);
- if (j < nb_numa_nodes) {
- core->proximity_domain = cpu_to_le32(j);
- }
+ core->proximity_domain = cpu_to_le32(node_id);
core->flags = cpu_to_le32(1);
}
}
@@ -2707,6 +2704,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
if (pcms->numa_nodes) {
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
+ if (have_numa_distance) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_slit(tables_blob, tables->linker);
+ }
}
if (acpi_get_mcfg(&mcfg)) {
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f3b372a18f..e36a375683 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -747,7 +747,9 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
{
FWCfgState *fw_cfg;
uint64_t *numa_fw_cfg;
- int i, j;
+ int i;
+ const CPUArchIdList *cpus;
+ MachineClass *mc = MACHINE_GET_CLASS(pcms);
fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
@@ -782,12 +784,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
*/
numa_fw_cfg = g_new0(uint64_t, 1 + pcms->apic_id_limit + nb_numa_nodes);
numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
- for (i = 0; i < max_cpus; i++) {
- unsigned int apic_id = x86_cpu_apic_id_from_index(i);
+ cpus = mc->possible_cpu_arch_ids(MACHINE(pcms));
+ for (i = 0; i < cpus->len; i++) {
+ unsigned int apic_id = cpus->cpus[i].arch_id;
assert(apic_id < pcms->apic_id_limit);
- j = numa_get_node_for_cpu(i);
- if (j < nb_numa_nodes) {
- numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
+ if (cpus->cpus[i].props.has_node_id) {
+ numa_fw_cfg[apic_id + 1] = cpu_to_le64(cpus->cpus[i].props.node_id);
}
}
for (i = 0; i < nb_numa_nodes; i++) {
@@ -1893,6 +1895,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
int idx;
+ int node_id;
CPUState *cs;
CPUArchId *cpu_slot;
X86CPUTopoInfo topo;
@@ -1982,6 +1985,22 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
cs = CPU(cpu);
cs->cpu_index = idx;
+
+ node_id = cpu_slot->props.node_id;
+ if (!cpu_slot->props.has_node_id) {
+ /* by default CPUState::numa_node was 0 if it's not set via CLI
+ * keep it this way for now but in future we probably should
+ * refuse to start up with incomplete numa mapping */
+ node_id = 0;
+ }
+ if (cs->numa_node == CPU_UNSET_NUMA_NODE_ID) {
+ cs->numa_node = node_id;
+ } else if (cs->numa_node != node_id) {
+ error_setg(errp, "node-id %d must match numa node specified"
+ "with -numa option for cpu-index %d",
+ cs->numa_node, cs->cpu_index);
+ return;
+ }
}
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
@@ -2243,12 +2262,14 @@ static void pc_machine_reset(void)
}
}
-static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index)
+static CpuInstanceProperties
+pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
{
- X86CPUTopoInfo topo;
- x86_topo_ids_from_idx(smp_cores, smp_threads, cpu_index,
- &topo);
- return topo.pkg_id;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+
+ assert(cpu_index < possible_cpus->len);
+ return possible_cpus->cpus[cpu_index].props;
}
static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
@@ -2280,6 +2301,15 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
ms->possible_cpus->cpus[i].props.core_id = topo.core_id;
ms->possible_cpus->cpus[i].props.has_thread_id = true;
ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id;
+
+ /* default distribution of CPUs over NUMA nodes */
+ if (nb_numa_nodes) {
+ /* preset values but do not enable them i.e. 'has_node_id = false',
+ * numa init code will enable them later if manual mapping wasn't
+ * present on CLI */
+ ms->possible_cpus->cpus[i].props.node_id =
+ topo.pkg_id % nb_numa_nodes;
+ }
}
return ms->possible_cpus;
}
@@ -2322,7 +2352,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
pcmc->acpi_data_size = 0x20000 + 0x8000;
pcmc->save_tsc_khz = true;
mc->get_hotplug_handler = pc_get_hotpug_handler;
- mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
+ mc->cpu_index_to_instance_props = pc_cpu_index_to_props;
mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
mc->has_hotpluggable_cpus = true;
mc->default_boot_order = "cad";
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9f102aa388..d468b963fb 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -54,6 +54,7 @@
#endif
#include "migration/migration.h"
#include "kvm_i386.h"
+#include "sysemu/numa.h"
#define MAX_IDE_BUS 2
@@ -442,6 +443,7 @@ static void pc_i440fx_2_9_machine_options(MachineClass *m)
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = 1;
+ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
}
DEFINE_I440FX_MACHINE(v2_9, "pc-i440fx-2.9", NULL,
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index dd792a8547..66303a78cf 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -47,6 +47,7 @@
#include "hw/usb.h"
#include "qemu/error-report.h"
#include "migration/migration.h"
+#include "sysemu/numa.h"
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
@@ -305,6 +306,7 @@ static void pc_q35_2_9_machine_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
+ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
}
DEFINE_Q35_MACHINE(v2_9, "pc-q35-2.9", NULL,
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 3ee0c1814a..46c038110c 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -484,12 +484,14 @@ static struct virtio_input_config virtio_tablet_config[] = {
.select = VIRTIO_INPUT_CFG_ABS_INFO,
.subsel = ABS_X,
.size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
+ .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
+ .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
},{
.select = VIRTIO_INPUT_CFG_ABS_INFO,
.subsel = ABS_Y,
.size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
+ .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
+ .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
},
{ /* end of list */ },
};
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 42e0e0ef84..dd93531ae3 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -213,6 +213,7 @@ static void ics_get_kvm_state(ICSState *ics)
irq->priority = irq->saved_priority;
}
+ irq->status = 0;
if (state & KVM_XICS_PENDING) {
if (state & KVM_XICS_LEVEL_SENSITIVE) {
irq->status |= XICS_STATUS_ASSERTED;
@@ -228,6 +229,12 @@ static void ics_get_kvm_state(ICSState *ics)
| XICS_STATUS_REJECTED;
}
}
+ if (state & KVM_XICS_PRESENTED) {
+ irq->status |= XICS_STATUS_PRESENTED;
+ }
+ if (state & KVM_XICS_QUEUED) {
+ irq->status |= XICS_STATUS_QUEUED;
+ }
}
}
@@ -265,6 +272,12 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
state |= KVM_XICS_PENDING;
}
}
+ if (irq->status & XICS_STATUS_PRESENTED) {
+ state |= KVM_XICS_PRESENTED;
+ }
+ if (irq->status & XICS_STATUS_QUEUED) {
+ state |= KVM_XICS_QUEUED;
+ }
ret = ioctl(kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
if (ret != 0) {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 68aaedc06d..bae1c0ac99 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -80,6 +80,8 @@
#define CLOCKFREQ (266UL * 1000UL * 1000UL)
#define BUSFREQ (100UL * 1000UL * 1000UL)
+#define NDRV_VGA_FILENAME "qemu_vga.ndrv"
+
/* UniN device */
static void unin_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
@@ -160,7 +162,8 @@ static void ppc_core99_init(MachineState *machine)
MACIOIDEState *macio_ide;
BusState *adb_bus;
MacIONVRAMState *nvr;
- int bios_size;
+ int bios_size, ndrv_size;
+ uint8_t *ndrv_file;
MemoryRegion *pic_mem, *escc_mem;
MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
int ppc_boot_device;
@@ -494,6 +497,19 @@ static void ppc_core99_init(MachineState *machine)
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_NVRAM_ADDR, nvram_addr);
+ /* MacOS NDRV VGA driver */
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME);
+ if (filename) {
+ ndrv_size = get_image_size(filename);
+ if (ndrv_size != -1) {
+ ndrv_file = g_malloc(ndrv_size);
+ ndrv_size = load_image(filename, ndrv_file);
+
+ fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size);
+ }
+ g_free(filename);
+ }
+
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 5df94e239b..97bb8541d7 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -53,6 +53,8 @@
#define CLOCKFREQ 266000000UL
#define BUSFREQ 66000000UL
+#define NDRV_VGA_FILENAME "qemu_vga.ndrv"
+
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
@@ -99,7 +101,8 @@ static void ppc_heathrow_init(MachineState *machine)
MACIOIDEState *macio_ide;
DeviceState *dev;
BusState *adb_bus;
- int bios_size;
+ int bios_size, ndrv_size;
+ uint8_t *ndrv_file;
MemoryRegion *pic_mem;
MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1);
uint16_t ppc_boot_device;
@@ -355,6 +358,19 @@ static void ppc_heathrow_init(MachineState *machine)
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
+ /* MacOS NDRV VGA driver */
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME);
+ if (filename) {
+ ndrv_size = get_image_size(filename);
+ if (ndrv_size != -1) {
+ ndrv_file = g_malloc(ndrv_size);
+ ndrv_size = load_image(filename, ndrv_file);
+
+ fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size);
+ }
+ g_free(filename);
+ }
+
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 6a498565c7..231ed9735b 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -511,7 +511,7 @@ static void ppc_powernv_reset(void)
* This is the internal simulator but it could also be an external
* BMC.
*/
- obj = object_resolve_path_type("", TYPE_IPMI_BMC, NULL);
+ obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
if (obj) {
pnv->bmc = IPMI_BMC(obj);
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 80d12d005c..0980d733cd 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -219,7 +219,7 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset,
/* 16: Vector */
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */
/* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 18 - 23 */
+ 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */
/* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */
/* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */
@@ -855,6 +855,8 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
* option vector 5: */
static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
{
+ PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
+
char val[2 * 3] = {
24, 0x00, /* Hash/Radix, filled in below. */
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
@@ -870,8 +872,13 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
val[1] = 0x00; /* Hash */
}
} else {
- /* TODO: TCG case, hash */
- val[1] = 0x00;
+ if (first_ppc_cpu->env.mmu_model & POWERPC_MMU_V3) {
+ /* V3 MMU supports both hash and radix (with dynamic switching) */
+ val[1] = 0xC0;
+ } else {
+ /* Otherwise we can only do hash */
+ val[1] = 0x00;
+ }
}
_FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
val, sizeof(val)));
@@ -2101,8 +2108,8 @@ static void ppc_spapr_init(MachineState *machine)
}
spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
- if (kvmppc_has_cap_mmu_radix()) {
- /* KVM always allows GTSE with radix... */
+ if (!kvm_enabled() || kvmppc_has_cap_mmu_radix()) {
+ /* KVM and TCG always allow GTSE with radix... */
spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
}
/* ... but not with hash (currently). */
@@ -2824,9 +2831,11 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
Error *local_err = NULL;
CPUCore *cc = CPU_CORE(dev);
+ sPAPRCPUCore *sc = SPAPR_CPU_CORE(dev);
char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
const char *type = object_get_typename(OBJECT(dev));
CPUArchId *core_slot;
+ int node_id;
int index;
if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
@@ -2861,6 +2870,21 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
goto out;
}
+ node_id = core_slot->props.node_id;
+ if (!core_slot->props.has_node_id) {
+ /* by default CPUState::numa_node was 0 if it's not set via CLI
+ * keep it this way for now but in future we probably should
+ * refuse to start up with incomplete numa mapping */
+ node_id = 0;
+ }
+ if (sc->node_id == CPU_UNSET_NUMA_NODE_ID) {
+ sc->node_id = node_id;
+ } else if (sc->node_id != node_id) {
+ error_setg(&local_err, "node-id %d must match numa node specified"
+ "with -numa option for cpu-index %d", sc->node_id, cc->core_id);
+ goto out;
+ }
+
out:
g_free(base_core_type);
error_propagate(errp, local_err);
@@ -2981,11 +3005,18 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
return NULL;
}
-static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index)
+static CpuInstanceProperties
+spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
{
- /* Allocate to NUMA nodes on a "socket" basis (not that concept of
- * socket means much for the paravirtualized PAPR platform) */
- return cpu_index / smp_threads / smp_cores;
+ CPUArchId *core_slot;
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+
+ /* make sure possible_cpu are intialized */
+ mc->possible_cpu_arch_ids(machine);
+ /* get CPU core slot containing thread that matches cpu_index */
+ core_slot = spapr_find_cpu_slot(machine, cpu_index, NULL);
+ assert(core_slot);
+ return core_slot->props;
}
static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
@@ -3012,8 +3043,15 @@ static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
machine->possible_cpus->cpus[i].arch_id = core_id;
machine->possible_cpus->cpus[i].props.has_core_id = true;
machine->possible_cpus->cpus[i].props.core_id = core_id;
- /* TODO: add 'has_node/node' here to describe
- to which node core belongs */
+
+ /* default distribution of CPUs over NUMA nodes */
+ if (nb_numa_nodes) {
+ /* preset values but do not enable them i.e. 'has_node_id = false',
+ * numa init code will enable them later if manual mapping wasn't
+ * present on CLI */
+ machine->possible_cpus->cpus[i].props.node_id =
+ core_id / smp_threads / smp_cores % nb_numa_nodes;
+ }
}
return machine->possible_cpus;
}
@@ -3138,7 +3176,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
hc->pre_plug = spapr_machine_device_pre_plug;
hc->plug = spapr_machine_device_plug;
hc->unplug = spapr_machine_device_unplug;
- mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
+ mc->cpu_index_to_instance_props = spapr_cpu_index_to_props;
mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
hc->unplug_request = spapr_machine_device_unplug_request;
@@ -3242,6 +3280,7 @@ static void spapr_machine_2_9_class_options(MachineClass *mc)
{
spapr_machine_2_10_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9);
+ mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
}
DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 4389ef4c2a..a17ea07ef1 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -176,13 +176,11 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
const char *typename = object_class_get_name(scc->cpu_class);
size_t size = object_type_get_instance_size(typename);
Error *local_err = NULL;
- int core_node_id = numa_get_node_for_cpu(cc->core_id);;
void *obj;
int i, j;
sc->threads = g_malloc0(size * cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
- int node_id;
char id[32];
CPUState *cs;
@@ -192,17 +190,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
cs = CPU(obj);
cs->cpu_index = cc->core_id + i;
- /* Set NUMA node for the added CPUs */
- node_id = numa_get_node_for_cpu(cs->cpu_index);
- if (node_id != core_node_id) {
- error_setg(&local_err, "Invalid node-id=%d of thread[cpu-index: %d]"
- " on CPU[core-id: %d, node-id: %d], node-id must be the same",
- node_id, cs->cpu_index, cc->core_id, core_node_id);
- goto err;
- }
- if (node_id < nb_numa_nodes) {
- cs->numa_node = node_id;
- }
+ /* Set NUMA node for the threads belonged to core */
+ cs->numa_node = sc->node_id;
snprintf(id, sizeof(id), "thread[%d]", i);
object_property_add_child(OBJECT(sc), id, obj, &local_err);
@@ -263,6 +252,11 @@ static const char *spapr_core_models[] = {
"POWER9_v1.0",
};
+static Property spapr_cpu_core_properties[] = {
+ DEFINE_PROP_INT32("node-id", sPAPRCPUCore, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_END_OF_LIST()
+};
+
void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -270,6 +264,7 @@ void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealizefn;
+ dc->props = spapr_cpu_core_properties;
scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data);
g_assert(scc->cpu_class);
}
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 9f18f75b88..0d608d6e28 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -936,7 +936,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
target_ulong opcode,
target_ulong *args)
{
- CPUPPCState *env = &cpu->env;
+ CPUState *cs;
target_ulong flags = args[0];
target_ulong proc_tbl = args[1];
target_ulong page_size = args[2];
@@ -992,16 +992,12 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
spapr_check_setup_free_hpt(spapr, spapr->patb_entry, cproc);
spapr->patb_entry = cproc; /* Save new process table */
- if ((flags & FLAG_RADIX) || (flags & FLAG_HASH_PROC_TBL)) {
- /* Use Process TBL */
- env->spr[SPR_LPCR] |= LPCR_UPRT;
- } else {
- env->spr[SPR_LPCR] &= ~LPCR_UPRT;
- }
- if (flags & FLAG_GTSE) { /* Partition Uses Guest Translation Shootdwn */
- env->spr[SPR_LPCR] |= LPCR_GTSE;
- } else {
- env->spr[SPR_LPCR] &= ~LPCR_GTSE;
+
+ /* Update the UPRT and GTSE bits in the LPCR for all cpus */
+ CPU_FOREACH(cs) {
+ set_spr(cs, SPR_LPCR, LPCR_UPRT | LPCR_GTSE,
+ ((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) |
+ ((flags & FLAG_GTSE) ? LPCR_GTSE : 0));
}
if (kvm_enabled()) {
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 9fe7333946..47b7519910 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -208,6 +208,7 @@ static void usb_hub_wakeup(USBPort *port1)
USBHubPort *port = &s->ports[port1->index];
if (port->wPortStatus & PORT_STAT_SUSPEND) {
+ port->wPortStatus &= ~PORT_STAT_SUSPEND;
port->wPortChange |= PORT_STAT_C_SUSPEND;
usb_wakeup(s->intr, 0);
}
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 6d5137383b..83a4f0e6fb 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -513,27 +513,18 @@ static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
{
USBDevice *dev;
Chardev *cdrv;
- uint32_t vendorid = 0, productid = 0;
char label[32];
static int index;
while (*filename && *filename != ':') {
const char *p;
- char *e;
+
if (strstart(filename, "vendorid=", &p)) {
- vendorid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus vendor ID %s", p);
- return NULL;
- }
- filename = e;
+ error_report("vendorid is not supported anymore");
+ return NULL;
} else if (strstart(filename, "productid=", &p)) {
- productid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus product ID %s", p);
- return NULL;
- }
- filename = e;
+ error_report("productid is not supported anymore");
+ return NULL;
} else {
error_report("unrecognized serial USB option %s", filename);
return NULL;
@@ -554,10 +545,7 @@ static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
dev = usb_create(bus, "usb-serial");
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- if (vendorid)
- qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
- if (productid)
- qdev_prop_set_uint16(&dev->qdev, "productid", productid);
+
return dev;
}
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index a2d3143bf4..77d8e1137a 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -50,7 +50,7 @@
/* Very pessimistic, let's hope it's enough for all cases */
#define EV_QUEUE (((3 * 24) + 16) * MAXSLOTS)
-#define TRB_LINK_LIMIT 4
+#define TRB_LINK_LIMIT 32
#define COMMAND_LIMIT 256
#define TRANSFER_LIMIT 256
@@ -1790,9 +1790,6 @@ static void xhci_stall_ep(XHCITransfer *xfer)
}
}
-static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx);
-
static int xhci_setup_packet(XHCITransfer *xfer)
{
USBEndpoint *ep;
@@ -1806,7 +1803,7 @@ static int xhci_setup_packet(XHCITransfer *xfer)
ep = xhci_epid_to_usbep(xfer->epctx);
if (!ep) {
DPRINTF("xhci: slot %d has no device\n",
- xfer->slotid);
+ xfer->epctx->slotid);
return -1;
}
}
@@ -1980,7 +1977,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
{
uint64_t mfindex;
- DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+ DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", epctx->slotid, epctx->epid);
xfer->in_xfer = epctx->type>>2;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index b001a27f05..ad5ef783a6 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -229,21 +229,10 @@ static void usbredir_log(void *priv, int level, const char *msg)
static void usbredir_log_data(USBRedirDevice *dev, const char *desc,
const uint8_t *data, int len)
{
- int i, j, n;
-
if (dev->debug < usbredirparser_debug_data) {
return;
}
-
- for (i = 0; i < len; i += j) {
- char buf[128];
-
- n = sprintf(buf, "%s", desc);
- for (j = 0; j < 8 && i + j < len; j++) {
- n += sprintf(buf + n, " %02X", data[i + j]);
- }
- error_report("%s", buf);
- }
+ qemu_hexdump((char *)data, stderr, desc, len);
}
/*