diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/acpi/aml-build.c | 26 | ||||
-rw-r--r-- | hw/acpi/cpu.c | 7 | ||||
-rw-r--r-- | hw/arm/virt-acpi-build.c | 19 | ||||
-rw-r--r-- | hw/arm/virt.c | 123 | ||||
-rw-r--r-- | hw/block/nvme.c | 26 | ||||
-rw-r--r-- | hw/block/nvme.h | 1 | ||||
-rw-r--r-- | hw/core/machine.c | 162 | ||||
-rw-r--r-- | hw/display/cg3.c | 41 | ||||
-rw-r--r-- | hw/display/sm501.c | 27 | ||||
-rw-r--r-- | hw/display/tcx.c | 68 | ||||
-rw-r--r-- | hw/display/vga.c | 2 | ||||
-rw-r--r-- | hw/display/virtio-gpu-3d.c | 16 | ||||
-rw-r--r-- | hw/display/virtio-gpu.c | 18 | ||||
-rw-r--r-- | hw/i386/acpi-build.c | 15 | ||||
-rw-r--r-- | hw/i386/pc.c | 54 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 2 | ||||
-rw-r--r-- | hw/i386/pc_q35.c | 2 | ||||
-rw-r--r-- | hw/input/virtio-input-hid.c | 6 | ||||
-rw-r--r-- | hw/intc/xics_kvm.c | 13 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 18 | ||||
-rw-r--r-- | hw/ppc/mac_oldworld.c | 18 | ||||
-rw-r--r-- | hw/ppc/pnv.c | 2 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 63 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 21 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 18 | ||||
-rw-r--r-- | hw/usb/dev-hub.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-serial.c | 24 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 9 | ||||
-rw-r--r-- | hw/usb/redirect.c | 13 |
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); } /* |