diff options
Diffstat (limited to 'hw')
39 files changed, 741 insertions, 208 deletions
diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c index 89fe0cda42..0f4d9b6f7a 100644 --- a/hw/core/machine-smp.c +++ b/hw/core/machine-smp.c @@ -197,3 +197,13 @@ void machine_parse_smp_config(MachineState *ms, return; } } + +unsigned int machine_topo_get_cores_per_socket(const MachineState *ms) +{ + return ms->smp.cores * ms->smp.clusters * ms->smp.dies; +} + +unsigned int machine_topo_get_threads_per_socket(const MachineState *ms) +{ + return ms->smp.threads * machine_topo_get_cores_per_socket(ms); +} diff --git a/hw/core/machine.c b/hw/core/machine.c index 46f8f9a2b0..f0d35c6401 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -41,6 +41,7 @@ GlobalProperty hw_compat_8_0[] = { { "migration", "multifd-flush-after-each-section", "on"}, + { TYPE_PCI_DEVICE, "x-pcie-ari-nextfn-1", "on" }, }; const size_t hw_compat_8_0_len = G_N_ELEMENTS(hw_compat_8_0); diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 15f9d99d09..e8ee03094e 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -31,6 +31,7 @@ typedef enum VhostUserGpuRequest { VHOST_USER_GPU_UPDATE, VHOST_USER_GPU_DMABUF_SCANOUT, VHOST_USER_GPU_DMABUF_UPDATE, + VHOST_USER_GPU_GET_EDID, } VhostUserGpuRequest; typedef struct VhostUserGpuDisplayInfoReply { @@ -78,6 +79,10 @@ typedef struct VhostUserGpuDMABUFScanout { int fd_drm_fourcc; } QEMU_PACKED VhostUserGpuDMABUFScanout; +typedef struct VhostUserGpuEdidRequest { + uint32_t scanout_id; +} QEMU_PACKED VhostUserGpuEdidRequest; + typedef struct VhostUserGpuMsg { uint32_t request; /* VhostUserGpuRequest */ uint32_t flags; @@ -88,6 +93,8 @@ typedef struct VhostUserGpuMsg { VhostUserGpuScanout scanout; VhostUserGpuUpdate update; VhostUserGpuDMABUFScanout dmabuf_scanout; + VhostUserGpuEdidRequest edid_req; + struct virtio_gpu_resp_edid resp_edid; struct virtio_gpu_resp_display_info display_info; uint64_t u64; } payload; @@ -99,6 +106,8 @@ static VhostUserGpuMsg m __attribute__ ((unused)); #define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4 +#define VHOST_USER_GPU_PROTOCOL_F_EDID 0 + static void vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked); static void @@ -161,6 +170,9 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) .request = msg->request, .flags = VHOST_USER_GPU_MSG_FLAG_REPLY, .size = sizeof(uint64_t), + .payload = { + .u64 = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID) + } }; vhost_user_gpu_send_msg(g, &reply); @@ -184,6 +196,26 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) vhost_user_gpu_send_msg(g, &reply); break; } + case VHOST_USER_GPU_GET_EDID: { + VhostUserGpuEdidRequest *m = &msg->payload.edid_req; + struct virtio_gpu_resp_edid resp = { {} }; + VhostUserGpuMsg reply = { + .request = msg->request, + .flags = VHOST_USER_GPU_MSG_FLAG_REPLY, + .size = sizeof(reply.payload.resp_edid), + }; + + if (m->scanout_id >= g->parent_obj.conf.max_outputs) { + error_report("invalid scanout: %d", m->scanout_id); + break; + } + + resp.hdr.type = VIRTIO_GPU_RESP_OK_EDID; + virtio_gpu_base_generate_edid(VIRTIO_GPU_BASE(g), m->scanout_id, &resp); + memcpy(&reply.payload.resp_edid, &resp, sizeof(resp)); + vhost_user_gpu_send_msg(g, &reply); + break; + } case VHOST_USER_GPU_SCANOUT: { VhostUserGpuScanout *m = &msg->payload.scanout; @@ -489,7 +521,7 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ @@ -506,7 +538,7 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index a29f191aa8..7ab7d08d0a 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -17,6 +17,7 @@ #include "migration/blocker.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "hw/display/edid.h" #include "trace.h" void @@ -51,6 +52,22 @@ virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, } } +void +virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, + struct virtio_gpu_resp_edid *edid) +{ + qemu_edid_info info = { + .width_mm = g->req_state[scanout].width_mm, + .height_mm = g->req_state[scanout].height_mm, + .prefx = g->req_state[scanout].width, + .prefy = g->req_state[scanout].height, + .refresh_rate = g->req_state[scanout].refresh_rate, + }; + + edid->size = cpu_to_le32(sizeof(edid->edid)); + qemu_edid_generate(edid->edid, sizeof(edid->edid), &info); +} + static void virtio_gpu_invalidate_display(void *opaque) { } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 347e17d490..befa7d6d78 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -24,7 +24,6 @@ #include "hw/virtio/virtio-gpu-bswap.h" #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/virtio/virtio-bus.h" -#include "hw/display/edid.h" #include "hw/qdev-properties.h" #include "qemu/log.h" #include "qemu/module.h" @@ -207,23 +206,6 @@ void virtio_gpu_get_display_info(VirtIOGPU *g, sizeof(display_info)); } -static void -virtio_gpu_generate_edid(VirtIOGPU *g, int scanout, - struct virtio_gpu_resp_edid *edid) -{ - VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); - qemu_edid_info info = { - .width_mm = b->req_state[scanout].width_mm, - .height_mm = b->req_state[scanout].height_mm, - .prefx = b->req_state[scanout].width, - .prefy = b->req_state[scanout].height, - .refresh_rate = b->req_state[scanout].refresh_rate, - }; - - edid->size = cpu_to_le32(sizeof(edid->edid)); - qemu_edid_generate(edid->edid, sizeof(edid->edid), &info); -} - void virtio_gpu_get_edid(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -242,7 +224,7 @@ void virtio_gpu_get_edid(VirtIOGPU *g, trace_virtio_gpu_cmd_get_edid(get_edid.scanout); memset(&edid, 0, sizeof(edid)); edid.hdr.type = VIRTIO_GPU_RESP_OK_EDID; - virtio_gpu_generate_edid(g, get_edid.scanout, &edid); + virtio_gpu_base_generate_edid(VIRTIO_GPU_BASE(g), get_edid.scanout, &edid); virtio_gpu_ctrl_response(g, cmd, &edid.hdr, sizeof(edid)); } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f9947fbc10..ac72e8f5be 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -114,7 +114,7 @@ static void pc_init1(MachineState *machine, X86MachineState *x86ms = X86_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_io = get_system_io(); - PCIBus *pci_bus; + PCIBus *pci_bus = NULL; ISABus *isa_bus; int piix3_devfn = -1; qemu_irq smi_irq; @@ -122,11 +122,10 @@ static void pc_init1(MachineState *machine, BusState *idebus[MAX_IDE_BUS]; ISADevice *rtc_state; MemoryRegion *ram_memory; - MemoryRegion *pci_memory; - MemoryRegion *rom_memory; + MemoryRegion *pci_memory = NULL; + MemoryRegion *rom_memory = system_memory; ram_addr_t lowmem; - uint64_t hole64_size; - DeviceState *i440fx_host; + uint64_t hole64_size = 0; /* * Calculate ram split, for memory below and above 4G. It's a bit @@ -198,18 +197,39 @@ static void pc_init1(MachineState *machine, } if (pcmc->pci_enabled) { + Object *phb; + pci_memory = g_new(MemoryRegion, 1); memory_region_init(pci_memory, NULL, "pci", UINT64_MAX); rom_memory = pci_memory; - i440fx_host = qdev_new(host_type); - hole64_size = object_property_get_uint(OBJECT(i440fx_host), + + phb = OBJECT(qdev_new(host_type)); + object_property_add_child(OBJECT(machine), "i440fx", phb); + object_property_set_link(phb, PCI_HOST_PROP_RAM_MEM, + OBJECT(ram_memory), &error_fatal); + object_property_set_link(phb, PCI_HOST_PROP_PCI_MEM, + OBJECT(pci_memory), &error_fatal); + object_property_set_link(phb, PCI_HOST_PROP_SYSTEM_MEM, + OBJECT(system_memory), &error_fatal); + object_property_set_link(phb, PCI_HOST_PROP_IO_MEM, + OBJECT(system_io), &error_fatal); + object_property_set_uint(phb, PCI_HOST_BELOW_4G_MEM_SIZE, + x86ms->below_4g_mem_size, &error_fatal); + object_property_set_uint(phb, PCI_HOST_ABOVE_4G_MEM_SIZE, + x86ms->above_4g_mem_size, &error_fatal); + object_property_set_str(phb, I440FX_HOST_PROP_PCI_TYPE, pci_type, + &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal); + + pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(phb), "pci.0")); + pci_bus_map_irqs(pci_bus, + xen_enabled() ? xen_pci_slot_get_pirq + : pc_pci_slot_get_pirq); + pcms->bus = pci_bus; + + hole64_size = object_property_get_uint(phb, PCI_HOST_PROP_PCI_HOLE64_SIZE, &error_abort); - } else { - pci_memory = NULL; - rom_memory = system_memory; - i440fx_host = NULL; - hole64_size = 0; } pc_guest_info_init(pcms); @@ -227,6 +247,9 @@ static void pc_init1(MachineState *machine, if (!xen_enabled()) { pc_memory_init(pcms, system_memory, rom_memory, hole64_size); } else { + assert(machine->ram_size == x86ms->below_4g_mem_size + + x86ms->above_4g_mem_size); + pc_system_flash_cleanup_unused(pcms); if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ @@ -240,19 +263,7 @@ static void pc_init1(MachineState *machine, PIIX3State *piix3; PCIDevice *pci_dev; - pci_bus = i440fx_init(pci_type, - i440fx_host, - system_memory, system_io, machine->ram_size, - x86ms->below_4g_mem_size, - x86ms->above_4g_mem_size, - pci_memory, ram_memory); - pci_bus_map_irqs(pci_bus, - xen_enabled() ? xen_pci_slot_get_pirq - : pc_pci_slot_get_pirq); - pcms->bus = pci_bus; - - pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, - TYPE_PIIX3_DEVICE); + pci_dev = pci_create_simple_multifunction(pci_bus, -1, TYPE_PIIX3_DEVICE); if (xen_enabled()) { pci_device_set_intx_routing_notifier( @@ -275,7 +286,6 @@ static void pc_init1(MachineState *machine, rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), "rtc")); } else { - pci_bus = NULL; isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 11a7084ea1..dc27a9e223 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -100,12 +100,12 @@ static int ehci_create_ich9_with_companions(PCIBus *bus, int slot) return -1; } - ehci = pci_new_multifunction(PCI_DEVFN(slot, 7), true, name); + ehci = pci_new_multifunction(PCI_DEVFN(slot, 7), name); pci_realize_and_unref(ehci, bus, &error_fatal); usbbus = QLIST_FIRST(&ehci->qdev.child_bus); for (i = 0; i < 3; i++) { - uhci = pci_new_multifunction(PCI_DEVFN(slot, comp[i].func), true, + uhci = pci_new_multifunction(PCI_DEVFN(slot, comp[i].func), comp[i].name); qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name); qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port); @@ -120,8 +120,7 @@ static void pc_q35_init(MachineState *machine) PCMachineState *pcms = PC_MACHINE(machine); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); X86MachineState *x86ms = X86_MACHINE(machine); - Q35PCIHost *q35_host; - PCIHostState *phb; + Object *phb; PCIBus *host_bus; PCIDevice *lpc; DeviceState *lpc_dev; @@ -207,10 +206,10 @@ static void pc_q35_init(MachineState *machine) } /* create pci host bus */ - q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE)); + phb = OBJECT(qdev_new(TYPE_Q35_HOST_DEVICE)); if (pcmc->pci_enabled) { - pci_hole64_size = object_property_get_uint(OBJECT(q35_host), + pci_hole64_size = object_property_get_uint(phb, PCI_HOST_PROP_PCI_HOLE64_SIZE, &error_abort); } @@ -218,25 +217,29 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ pc_memory_init(pcms, system_memory, rom_memory, pci_hole64_size); - object_property_add_child(OBJECT(machine), "q35", OBJECT(q35_host)); - object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_RAM_MEM, + object_property_add_child(OBJECT(machine), "q35", phb); + object_property_set_link(phb, PCI_HOST_PROP_RAM_MEM, OBJECT(machine->ram), NULL); - object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_PCI_MEM, + object_property_set_link(phb, PCI_HOST_PROP_PCI_MEM, OBJECT(pci_memory), NULL); - object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_SYSTEM_MEM, + object_property_set_link(phb, PCI_HOST_PROP_SYSTEM_MEM, OBJECT(system_memory), NULL); - object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_IO_MEM, + object_property_set_link(phb, PCI_HOST_PROP_IO_MEM, OBJECT(system_io), NULL); - object_property_set_int(OBJECT(q35_host), PCI_HOST_BELOW_4G_MEM_SIZE, + object_property_set_int(phb, PCI_HOST_BELOW_4G_MEM_SIZE, x86ms->below_4g_mem_size, NULL); - object_property_set_int(OBJECT(q35_host), PCI_HOST_ABOVE_4G_MEM_SIZE, + object_property_set_int(phb, PCI_HOST_ABOVE_4G_MEM_SIZE, x86ms->above_4g_mem_size, NULL); + object_property_set_bool(phb, PCI_HOST_BYPASS_IOMMU, + pcms->default_bus_bypass_iommu, NULL); + sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal); + /* pci */ - sysbus_realize_and_unref(SYS_BUS_DEVICE(q35_host), &error_fatal); - phb = PCI_HOST_BRIDGE(q35_host); - host_bus = phb->bus; + host_bus = PCI_BUS(qdev_get_child_bus(DEVICE(phb), "pcie.0")); + pcms->bus = host_bus; + /* create ISA bus */ - lpc = pci_new_multifunction(PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC), true, + lpc = pci_new_multifunction(PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC), TYPE_ICH9_LPC_DEVICE); qdev_prop_set_bit(DEVICE(lpc), "smm-enabled", x86_machine_is_smm_enabled(x86ms)); @@ -301,7 +304,7 @@ static void pc_q35_init(MachineState *machine) ahci = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_SATA1_DEV, ICH9_SATA1_FUNC), - true, "ich9-ahci"); + "ich9-ahci"); idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); @@ -323,7 +326,7 @@ static void pc_q35_init(MachineState *machine) smb = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), - true, TYPE_ICH9_SMB_DEVICE); + TYPE_ICH9_SMB_DEVICE); pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(smb), "i2c")); smbus_eeprom_init(pcms->smbus, 8, NULL, 0); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 21ad844519..4e11ff6cd6 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -770,8 +770,7 @@ static void boston_mach_init(MachineState *machine) boston_lcd_event, NULL, s, NULL, true); ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, - PCI_DEVFN(0, 0), - true, TYPE_ICH9_AHCI); + PCI_DEVFN(0, 0), TYPE_ICH9_AHCI); g_assert(ARRAY_SIZE(hd) == ahci_get_num_ports(ahci)); ide_drive_get(hd, ahci_get_num_ports(ahci)); ahci_ide_create_devs(ahci, hd); diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index cfc8ca6ae4..c827f615f3 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -297,7 +297,7 @@ static void mips_fuloong2e_init(MachineState *machine) /* South bridge -> IP5 */ pci_dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(FULOONG2E_VIA_SLOT, 0), - true, TYPE_VT82C686B_ISA); + TYPE_VT82C686B_ISA); object_property_add_alias(OBJECT(machine), "rtc-time", object_resolve_path_component(OBJECT(pci_dev), "rtc"), diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 47cb49f691..f9618fa5f5 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1251,7 +1251,7 @@ void mips_malta_init(MachineState *machine) pci_bus_map_irqs(pci_bus, malta_pci_slot_get_pirq); /* Southbridge */ - piix4 = pci_create_simple_multifunction(pci_bus, PIIX4_PCI_DEVFN, true, + piix4 = pci_create_simple_multifunction(pci_bus, PIIX4_PCI_DEVFN, TYPE_PIIX4_PCI_DEVICE); isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0")); diff --git a/hw/net/igb.c b/hw/net/igb.c index 1c989d7677..8ff832acfc 100644 --- a/hw/net/igb.c +++ b/hw/net/igb.c @@ -431,7 +431,7 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp) hw_error("Failed to initialize AER capability"); } - pcie_ari_init(pci_dev, 0x150, 1); + pcie_ari_init(pci_dev, 0x150); pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF, IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS, diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c index 284ea61184..d55e1e8a6a 100644 --- a/hw/net/igbvf.c +++ b/hw/net/igbvf.c @@ -270,7 +270,7 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp) hw_error("Failed to initialize AER capability"); } - pcie_ari_init(dev, 0x150, 1); + pcie_ari_init(dev, 0x150); } static void igbvf_pci_uninit(PCIDevice *dev) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 04783f5b94..7102ec4817 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3362,7 +3362,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) } /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return false */ @@ -3394,7 +3394,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, } /* *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ @@ -3951,6 +3951,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->vmsd = &vmstate_virtio_net_device; vdc->primary_unplug_pending = primary_unplug_pending; vdc->get_vhost = virtio_net_get_vhost; + vdc->toggle_device_iotlb = vhost_toggle_device_iotlb; } static const TypeInfo virtio_net_info = { diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 355668bdf8..8e8e870b9a 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -8120,7 +8120,7 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) pcie_endpoint_cap_init(pci_dev, 0x80); pcie_cap_flr_init(pci_dev); if (n->params.sriov_max_vfs) { - pcie_ari_init(pci_dev, 0x100, 1); + pcie_ari_init(pci_dev, 0x100); } /* add one to max_ioqpairs to account for the admin queue pair */ diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 61e7b97ff4..62d6287681 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -27,7 +27,6 @@ #include "qemu/range.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" -#include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/pci-host/i440fx.h" #include "hw/qdev-properties.h" @@ -47,10 +46,19 @@ OBJECT_DECLARE_SIMPLE_TYPE(I440FXState, I440FX_PCI_HOST_BRIDGE) struct I440FXState { PCIHostState parent_obj; + + MemoryRegion *system_memory; + MemoryRegion *io_memory; + MemoryRegion *pci_address_space; + MemoryRegion *ram_memory; Range pci_hole; + uint64_t below_4g_mem_size; + uint64_t above_4g_mem_size; uint64_t pci_hole64_size; bool pci_hole64_fix; uint32_t short_root_bus; + + char *pci_type; }; #define I440FX_PAM 0x59 @@ -65,6 +73,15 @@ struct I440FXState { */ #define I440FX_COREBOOT_RAM_SIZE 0x57 +static void i440fx_realize(PCIDevice *dev, Error **errp) +{ + dev->config[I440FX_SMRAM] = 0x02; + + if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + warn_report("i440fx doesn't support emulated iommu"); + } +} + static void i440fx_update_memory_mappings(PCII440FXState *d) { int i; @@ -205,80 +222,69 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, static void i440fx_pcihost_initfn(Object *obj) { - PCIHostState *s = PCI_HOST_BRIDGE(obj); + I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); + PCIHostState *phb = PCI_HOST_BRIDGE(obj); - memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s, + memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops, phb, "pci-conf-idx", 4); - memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s, + memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb, "pci-conf-data", 4); -} -static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) -{ - PCIHostState *s = PCI_HOST_BRIDGE(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + object_property_add_link(obj, PCI_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, + (Object **) &s->ram_memory, + qdev_prop_allow_set_link_before_realize, 0); - memory_region_add_subregion(s->bus->address_space_io, 0xcf8, &s->conf_mem); - sysbus_init_ioports(sbd, 0xcf8, 4); + object_property_add_link(obj, PCI_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, + (Object **) &s->pci_address_space, + qdev_prop_allow_set_link_before_realize, 0); - memory_region_add_subregion(s->bus->address_space_io, 0xcfc, &s->data_mem); - sysbus_init_ioports(sbd, 0xcfc, 4); + object_property_add_link(obj, PCI_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, + (Object **) &s->system_memory, + qdev_prop_allow_set_link_before_realize, 0); - /* register i440fx 0xcf8 port as coalesced pio */ - memory_region_set_flush_coalesced(&s->data_mem); - memory_region_add_coalescing(&s->conf_mem, 0, 4); + object_property_add_link(obj, PCI_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, + (Object **) &s->io_memory, + qdev_prop_allow_set_link_before_realize, 0); } -static void i440fx_realize(PCIDevice *dev, Error **errp) -{ - dev->config[I440FX_SMRAM] = 0x02; - - if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { - warn_report("i440fx doesn't support emulated iommu"); - } -} - -PCIBus *i440fx_init(const char *pci_type, - DeviceState *dev, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, - MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) +static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) { + ERRP_GUARD(); + I440FXState *s = I440FX_PCI_HOST_BRIDGE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); PCIBus *b; PCIDevice *d; - PCIHostState *s; PCII440FXState *f; unsigned i; - I440FXState *i440fx; - s = PCI_HOST_BRIDGE(dev); - b = pci_root_bus_new(dev, NULL, pci_address_space, - address_space_io, 0, TYPE_PCI_BUS); - s->bus = b; - object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_add_subregion(s->io_memory, 0xcf8, &phb->conf_mem); + sysbus_init_ioports(sbd, 0xcf8, 4); + + memory_region_add_subregion(s->io_memory, 0xcfc, &phb->data_mem); + sysbus_init_ioports(sbd, 0xcfc, 4); - d = pci_create_simple(b, 0, pci_type); + /* register i440fx 0xcf8 port as coalesced pio */ + memory_region_set_flush_coalesced(&phb->data_mem); + memory_region_add_coalescing(&phb->conf_mem, 0, 4); + + b = pci_root_bus_new(dev, NULL, s->pci_address_space, + s->io_memory, 0, TYPE_PCI_BUS); + phb->bus = b; + + d = pci_create_simple(b, 0, s->pci_type); f = I440FX_PCI_DEVICE(d); - f->system_memory = address_space_mem; - f->pci_address_space = pci_address_space; - f->ram_memory = ram_memory; - i440fx = I440FX_PCI_HOST_BRIDGE(dev); - range_set_bounds(&i440fx->pci_hole, below_4g_mem_size, + range_set_bounds(&s->pci_hole, s->below_4g_mem_size, IO_APIC_DEFAULT_ADDRESS - 1); /* setup pci memory mapping */ - pc_pci_as_mapping_init(f->system_memory, f->pci_address_space); + pc_pci_as_mapping_init(s->system_memory, s->pci_address_space); /* if *disabled* show SMRAM to all CPUs */ memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region", - f->pci_address_space, 0xa0000, 0x20000); - memory_region_add_subregion_overlap(f->system_memory, 0xa0000, + s->pci_address_space, SMRAM_C_BASE, SMRAM_C_SIZE); + memory_region_add_subregion_overlap(s->system_memory, SMRAM_C_BASE, &f->smram_region, 1); memory_region_set_enabled(&f->smram_region, true); @@ -286,20 +292,21 @@ PCIBus *i440fx_init(const char *pci_type, memory_region_init(&f->smram, OBJECT(d), "smram", 4 * GiB); memory_region_set_enabled(&f->smram, true); memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low", - f->ram_memory, 0xa0000, 0x20000); + s->ram_memory, SMRAM_C_BASE, SMRAM_C_SIZE); memory_region_set_enabled(&f->low_smram, true); - memory_region_add_subregion(&f->smram, 0xa0000, &f->low_smram); + memory_region_add_subregion(&f->smram, SMRAM_C_BASE, &f->low_smram); object_property_add_const_link(qdev_get_machine(), "smram", OBJECT(&f->smram)); - init_pam(&f->pam_regions[0], OBJECT(d), f->ram_memory, f->system_memory, - f->pci_address_space, PAM_BIOS_BASE, PAM_BIOS_SIZE); + init_pam(&f->pam_regions[0], OBJECT(d), s->ram_memory, s->system_memory, + s->pci_address_space, PAM_BIOS_BASE, PAM_BIOS_SIZE); for (i = 0; i < ARRAY_SIZE(f->pam_regions) - 1; ++i) { - init_pam(&f->pam_regions[i + 1], OBJECT(d), f->ram_memory, - f->system_memory, f->pci_address_space, + init_pam(&f->pam_regions[i + 1], OBJECT(d), s->ram_memory, + s->system_memory, s->pci_address_space, PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } + ram_addr_t ram_size = s->below_4g_mem_size + s->above_4g_mem_size; ram_size = ram_size / 8 / 1024 / 1024; if (ram_size > 255) { ram_size = 255; @@ -307,8 +314,6 @@ PCIBus *i440fx_init(const char *pci_type, d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size; i440fx_update_memory_mappings(f); - - return b; } static void i440fx_class_init(ObjectClass *klass, void *data) @@ -359,7 +364,12 @@ static Property i440fx_props[] = { DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState, pci_hole64_size, I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT), DEFINE_PROP_UINT32("short_root_bus", I440FXState, short_root_bus, 0), + DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, I440FXState, + below_4g_mem_size, 0), + DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, I440FXState, + above_4g_mem_size, 0), DEFINE_PROP_BOOL("x-pci-hole64-fix", I440FXState, pci_hole64_fix, true), + DEFINE_PROP_STRING(I440FX_HOST_PROP_PCI_TYPE, I440FXState, pci_type), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index fd18920e7f..91c46df9ae 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -66,9 +66,7 @@ static void q35_host_realize(DeviceState *dev, Error **errp) s->mch.pci_address_space, s->mch.address_space_io, 0, TYPE_PCIE_BUS); - PC_MACHINE(qdev_get_machine())->bus = pci->bus; - pci->bypass_iommu = - PC_MACHINE(qdev_get_machine())->default_bus_bypass_iommu; + qdev_realize(DEVICE(&s->mch), BUS(pci->bus), &error_fatal); } @@ -242,19 +240,19 @@ static void q35_host_initfn(Object *obj) object_property_add_uint64_ptr(obj, PCIE_HOST_MCFG_SIZE, &pehb->size, OBJ_PROP_FLAG_READ); - object_property_add_link(obj, MCH_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, + object_property_add_link(obj, PCI_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.ram_memory, qdev_prop_allow_set_link_before_realize, 0); - object_property_add_link(obj, MCH_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, + object_property_add_link(obj, PCI_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.pci_address_space, qdev_prop_allow_set_link_before_realize, 0); - object_property_add_link(obj, MCH_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, + object_property_add_link(obj, PCI_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.system_memory, qdev_prop_allow_set_link_before_realize, 0); - object_property_add_link(obj, MCH_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, + object_property_add_link(obj, PCI_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, (Object **) &s->mch.address_space_io, qdev_prop_allow_set_link_before_realize, 0); } @@ -285,7 +283,6 @@ static void blackhole_write(void *opaque, hwaddr addr, uint64_t val, static const MemoryRegionOps blackhole_ops = { .read = blackhole_read, .write = blackhole_write, - .endianness = DEVICE_NATIVE_ENDIAN, .valid.min_access_size = 1, .valid.max_access_size = 4, .impl.min_access_size = 4, diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index 949ecc21f2..dcb2e230b6 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -387,14 +387,12 @@ static void sabre_realize(DeviceState *dev, Error **errp) pci_setup_iommu(phb->bus, sabre_pci_dma_iommu, s->iommu); /* APB secondary busses */ - pci_dev = pci_new_multifunction(PCI_DEVFN(1, 0), true, - TYPE_SIMBA_PCI_BRIDGE); + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 0), TYPE_SIMBA_PCI_BRIDGE); s->bridgeB = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(s->bridgeB, "pciB", pci_simbaB_map_irq); pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); - pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), true, - TYPE_SIMBA_PCI_BRIDGE); + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), TYPE_SIMBA_PCI_BRIDGE); s->bridgeA = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(s->bridgeA, "pciA", pci_simbaA_map_irq); pci_realize_and_unref(pci_dev, phb->bus, &error_fatal); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e2eb4c3b4a..784c02a182 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -65,6 +65,7 @@ bool pci_available = true; static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset(BusState *qbus); +static bool pcie_has_upstream_port(PCIDevice *dev); static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), @@ -82,6 +83,8 @@ static Property pci_props[] = { DEFINE_PROP_UINT32("acpi-index", PCIDevice, acpi_index, 0), DEFINE_PROP_BIT("x-pcie-err-unc-mask", PCIDevice, cap_present, QEMU_PCIE_ERR_UNC_MASK_BITNR, true), + DEFINE_PROP_BIT("x-pcie-ari-nextfn-1", PCIDevice, cap_present, + QEMU_PCIE_ARI_NEXTFN_1_BITNR, false), DEFINE_PROP_END_OF_LIST() }; @@ -2121,6 +2124,25 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } } + /* + * A PCIe Downstream Port that do not have ARI Forwarding enabled must + * associate only Device 0 with the device attached to the bus + * representing the Link from the Port (PCIe base spec rev 4.0 ver 0.3, + * sec 7.3.1). + * With ARI, PCI_SLOT() can return non-zero value as the traditional + * 5-bit Device Number and 3-bit Function Number fields in its associated + * Routing IDs, Requester IDs and Completer IDs are interpreted as a + * single 8-bit Function Number. Hence, ignore ARI capable devices. + */ + if (pci_is_express(pci_dev) && + !pcie_find_capability(pci_dev, PCI_EXT_CAP_ID_ARI) && + pcie_has_upstream_port(pci_dev) && + PCI_SLOT(pci_dev->devfn)) { + warn_report("PCI: slot %d is not valid for %s," + " parent device only allows plugging into slot 0.", + PCI_SLOT(pci_dev->devfn), pci_dev->name); + } + if (pci_dev->failover_pair_id) { if (!pci_bus_is_express(pci_get_bus(pci_dev))) { error_setg(errp, "failover primary device must be on " @@ -2164,8 +2186,8 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) pci_dev->msi_trigger = pci_msi_trigger; } -PCIDevice *pci_new_multifunction(int devfn, bool multifunction, - const char *name) +static PCIDevice *pci_new_internal(int devfn, bool multifunction, + const char *name) { DeviceState *dev; @@ -2175,9 +2197,14 @@ PCIDevice *pci_new_multifunction(int devfn, bool multifunction, return PCI_DEVICE(dev); } +PCIDevice *pci_new_multifunction(int devfn, const char *name) +{ + return pci_new_internal(devfn, true, name); +} + PCIDevice *pci_new(int devfn, const char *name) { - return pci_new_multifunction(devfn, false, name); + return pci_new_internal(devfn, false, name); } bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp) @@ -2186,17 +2213,18 @@ bool pci_realize_and_unref(PCIDevice *dev, PCIBus *bus, Error **errp) } PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, - bool multifunction, const char *name) { - PCIDevice *dev = pci_new_multifunction(devfn, multifunction, name); + PCIDevice *dev = pci_new_multifunction(devfn, name); pci_realize_and_unref(dev, bus, &error_fatal); return dev; } PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) { - return pci_create_simple_multifunction(bus, devfn, false, name); + PCIDevice *dev = pci_new(devfn, name); + pci_realize_and_unref(dev, bus, &error_fatal); + return dev; } static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index dfd185bbb4..7af8afdcbe 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -232,7 +232,7 @@ const VMStateDescription vmstate_pcihost = { static Property pci_host_properties_common[] = { DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState, mig_enabled, true), - DEFINE_PROP_BOOL("bypass-iommu", PCIHostState, bypass_iommu, false), + DEFINE_PROP_BOOL(PCI_HOST_BYPASS_IOMMU, PCIHostState, bypass_iommu, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index b7f107ed8d..6db0cf69cd 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -666,6 +666,10 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s) pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, PCI_EXP_HP_EV_SUPPORTED); + /* Avoid migration abortion when this device hot-removed by guest */ + pci_word_test_and_clear_mask(dev->cmask + pos + PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDS); + dev->exp.hpev_notified = false; qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))), @@ -1035,8 +1039,10 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev) */ /* ARI */ -void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) +void pcie_ari_init(PCIDevice *dev, uint16_t offset) { + uint16_t nextfn = dev->cap_present & QEMU_PCIE_ARI_NEXTFN_1 ? 1 : 0; + pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, offset, PCI_ARI_SIZEOF); pci_set_long(dev->config + offset + PCI_ARI_CAP, (nextfn & 0xff) << 8); diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index aa5a757b11..76a3b6917e 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -211,6 +211,7 @@ static void unregister_vfs(PCIDevice *dev) error_free(local_err); } object_unparent(OBJECT(vf)); + object_unref(OBJECT(vf)); } g_free(dev->exp.sriov_pf.vf); dev->exp.sriov_pf.vf = NULL; diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 9c9944188b..4447bbe8ec 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -180,7 +180,7 @@ static void pegasos2_init(MachineState *machine) /* VIA VT8231 South Bridge (multifunction PCI device) */ via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), - true, TYPE_VT8231_ISA)); + TYPE_VT8231_ISA)); for (i = 0; i < PCI_NUM_PINS; i++) { pm->via_pirq[i] = qdev_get_gpio_in_named(DEVICE(via), "pirq", i); } diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index d2007e70fb..10cd22f610 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -713,6 +713,8 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) { char sock_str[128]; size_t tbl_len = SMBIOS_TYPE_4_LEN_V28; + unsigned threads_per_socket; + unsigned cores_per_socket; if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_64) { tbl_len = SMBIOS_TYPE_4_LEN_V30; @@ -747,17 +749,20 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); - t->core_count = (ms->smp.cores > 255) ? 0xFF : ms->smp.cores; + threads_per_socket = machine_topo_get_threads_per_socket(ms); + cores_per_socket = machine_topo_get_cores_per_socket(ms); + + t->core_count = (cores_per_socket > 255) ? 0xFF : cores_per_socket; t->core_enabled = t->core_count; - t->thread_count = (ms->smp.threads > 255) ? 0xFF : ms->smp.threads; + t->thread_count = (threads_per_socket > 255) ? 0xFF : threads_per_socket; t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ t->processor_family2 = cpu_to_le16(0x01); /* Other */ if (tbl_len == SMBIOS_TYPE_4_LEN_V30) { - t->core_count2 = t->core_enabled2 = cpu_to_le16(ms->smp.cores); - t->thread_count2 = cpu_to_le16(ms->smp.threads); + t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket); + t->thread_count2 = cpu_to_le16(threads_per_socket); } SMBIOS_BUILD_TABLE_POST; @@ -1088,8 +1093,7 @@ void smbios_get_tables(MachineState *ms, smbios_build_type_2_table(); smbios_build_type_3_table(); - smbios_smp_sockets = DIV_ROUND_UP(ms->smp.cpus, - ms->smp.cores * ms->smp.threads); + smbios_smp_sockets = ms->smp.sockets; assert(smbios_smp_sockets >= 1); for (i = 0; i < smbios_smp_sockets; i++) { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 29e9b6cc26..d908a38f73 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -612,7 +612,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_bus_set_slot_reserved_mask(pci_busA, 0xfffffff1); pci_bus_set_slot_reserved_mask(pci_busB, 0xfffffff0); - ebus = pci_new_multifunction(PCI_DEVFN(1, 0), true, TYPE_EBUS); + ebus = pci_new_multifunction(PCI_DEVFN(1, 0), TYPE_EBUS); qdev_prop_set_uint64(DEVICE(ebus), "console-serial-base", hwdef->console_serial_base); pci_realize_and_unref(ebus, pci_busA, &error_fatal); @@ -648,8 +648,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, if (!nd->model || strcmp(nd->model, mc->default_nic) == 0) { if (!onboard_nic) { - pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), - true, mc->default_nic); + pci_dev = pci_new_multifunction(PCI_DEVFN(1, 1), mc->default_nic); bus = pci_busA; memcpy(&macaddr, &nd->macaddr.a, sizeof(MACAddr)); onboard_nic = true; diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index de7a35429a..a9ee09062f 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -96,3 +96,8 @@ config VHOST_VDPA_DEV bool default y depends on VIRTIO && VHOST_VDPA && LINUX + +config VHOST_USER_SCMI + bool + default y + depends on VIRTIO && VHOST_USER diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index f32b22f61b..c4f4fe05fa 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -35,6 +35,8 @@ specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c')) specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c')) +specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 8f8d05cf9b..7109cf1a3b 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -34,7 +34,9 @@ vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_ vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 +vhost_vdpa_listener_region_add_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64 vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" +vhost_vdpa_listener_region_del_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64 vhost_vdpa_listener_region_del(void *vdpa, uint64_t iova, uint64_t llend) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64 vhost_vdpa_add_status(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8 vhost_vdpa_init(void *dev, void *vdpa) "dev: %p vdpa: %p" @@ -44,7 +46,7 @@ vhost_vdpa_set_mem_table(void *dev, uint32_t nregions, uint32_t padding) "dev: % vhost_vdpa_dump_regions(void *dev, int i, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint64_t flags_padding) "dev: %p %d: guest_phys_addr: 0x%"PRIx64" memory_size: 0x%"PRIx64" userspace_addr: 0x%"PRIx64" flags_padding: 0x%"PRIx64 vhost_vdpa_set_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRIx64 vhost_vdpa_get_device_id(void *dev, uint32_t device_id) "dev: %p device_id %"PRIu32 -vhost_vdpa_reset_device(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8 +vhost_vdpa_reset_device(void *dev) "dev: %p" vhost_vdpa_get_vq_index(void *dev, int idx, int vq_idx) "dev: %p idx: %d vq idx: %d" vhost_vdpa_set_vring_ready(void *dev) "dev: %p" vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s" @@ -131,6 +133,7 @@ virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "m virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s" virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s" virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)" +virtio_iommu_freeze_granule(uint64_t page_size_mask) "granule set to 0x%"PRIx64 # virtio-mem.c virtio_mem_send_response(uint16_t type) "type=%" PRIu16 diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index 1b1d85306c..49e5aed931 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -111,7 +111,7 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, addrs[i] = map->iova + off; needle_last = int128_add(int128_make64(needle.translated_addr), - int128_make64(iovec[i].iov_len)); + int128_makes64(iovec[i].iov_len - 1)); map_last = int128_make64(map->translated_addr + map->size); if (unlikely(int128_gt(needle_last, map_last))) { qemu_log_mask(LOG_GUEST_ERROR, diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c index c175148fce..aa858ef3fb 100644 --- a/hw/virtio/vhost-stub.c +++ b/hw/virtio/vhost-stub.c @@ -15,3 +15,7 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) void vhost_user_cleanup(VhostUserState *user) { } + +void vhost_toggle_device_iotlb(VirtIODevice *vdev) +{ +} diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index 83fc20e49e..49d699ffc2 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -161,7 +161,7 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ @@ -177,7 +177,7 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c index d6927b610a..3b013f2d0f 100644 --- a/hw/virtio/vhost-user-gpio.c +++ b/hw/virtio/vhost-user-gpio.c @@ -194,7 +194,7 @@ static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ diff --git a/hw/virtio/vhost-user-scmi-pci.c b/hw/virtio/vhost-user-scmi-pci.c new file mode 100644 index 0000000000..7f53af7fce --- /dev/null +++ b/hw/virtio/vhost-user-scmi-pci.c @@ -0,0 +1,68 @@ +/* + * Vhost-user SCMI virtio device PCI glue + * + * SPDX-FileCopyrightText: Red Hat, Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-scmi.h" +#include "hw/virtio/virtio-pci.h" + +struct VHostUserSCMIPCI { + VirtIOPCIProxy parent_obj; + VHostUserSCMI vdev; +}; + +typedef struct VHostUserSCMIPCI VHostUserSCMIPCI; + +#define TYPE_VHOST_USER_SCMI_PCI "vhost-user-scmi-pci-base" + +DECLARE_INSTANCE_CHECKER(VHostUserSCMIPCI, VHOST_USER_SCMI_PCI, + TYPE_VHOST_USER_SCMI_PCI) + +static void vhost_user_scmi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserSCMIPCI *dev = VHOST_USER_SCMI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + vpci_dev->nvectors = 1; + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void vhost_user_scmi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_scmi_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */ + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_user_scmi_pci_instance_init(Object *obj) +{ + VHostUserSCMIPCI *dev = VHOST_USER_SCMI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_SCMI); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_scmi_pci_info = { + .base_name = TYPE_VHOST_USER_SCMI_PCI, + .non_transitional_name = "vhost-user-scmi-pci", + .instance_size = sizeof(VHostUserSCMIPCI), + .instance_init = vhost_user_scmi_pci_instance_init, + .class_init = vhost_user_scmi_pci_class_init, +}; + +static void vhost_user_scmi_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_scmi_pci_info); +} + +type_init(vhost_user_scmi_pci_register); diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c new file mode 100644 index 0000000000..d386fb2df9 --- /dev/null +++ b/hw/virtio/vhost-user-scmi.c @@ -0,0 +1,306 @@ +/* + * Vhost-user SCMI virtio device + * + * SPDX-FileCopyrightText: Red Hat, Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Implementation based on other vhost-user devices in QEMU. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/vhost-user-scmi.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_scmi.h" +#include "trace.h" + +/* + * In this version, we don't support VIRTIO_SCMI_F_SHARED_MEMORY. + * Note that VIRTIO_SCMI_F_SHARED_MEMORY is currently not supported in + * Linux VirtIO SCMI guest driver. + */ +static const int feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_SCMI_F_P2A_CHANNELS, + VHOST_INVALID_FEATURE_BIT +}; + +static int vu_scmi_start(VirtIODevice *vdev) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + struct vhost_dev *vhost_dev = &scmi->vhost_dev; + int ret, i; + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(vhost_dev, vdev); + if (ret < 0) { + error_report("Error enabling host notifiers: %d", ret); + return ret; + } + + ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier: %d", ret); + goto err_host_notifiers; + } + + vhost_ack_features(&scmi->vhost_dev, feature_bits, vdev->guest_features); + + ret = vhost_dev_start(&scmi->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-scmi: %d", ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < scmi->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&scmi->vhost_dev, vdev, i, false); + } + return 0; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(vhost_dev, vdev); + + return ret; +} + +static void vu_scmi_stop(VirtIODevice *vdev) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + struct vhost_dev *vhost_dev = &scmi->vhost_dev; + int ret; + + if (!k->set_guest_notifiers) { + return; + } + + vhost_dev_stop(vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + vhost_dev_disable_notifiers(vhost_dev, vdev); +} + +static void vu_scmi_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + bool should_start = virtio_device_should_start(vdev, status); + + if (!scmi->connected) { + return; + } + if (vhost_dev_is_started(&scmi->vhost_dev) == should_start) { + return; + } + + if (should_start) { + vu_scmi_start(vdev); + } else { + vu_scmi_stop(vdev); + } +} + +static uint64_t vu_scmi_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + + return vhost_get_features(&scmi->vhost_dev, feature_bits, features); +} + +static void vu_scmi_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ +} + +static void vu_scmi_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { + return; + } + + vhost_virtqueue_mask(&scmi->vhost_dev, vdev, idx, mask); +} + +static bool vu_scmi_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + + return vhost_virtqueue_pending(&scmi->vhost_dev, idx); +} + +static void vu_scmi_connect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + + if (scmi->connected) { + return; + } + scmi->connected = true; + + /* restore vhost state */ + if (virtio_device_started(vdev, vdev->status)) { + vu_scmi_start(vdev); + } +} + +static void vu_scmi_disconnect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); + + if (!scmi->connected) { + return; + } + scmi->connected = false; + + if (vhost_dev_is_started(&scmi->vhost_dev)) { + vu_scmi_stop(vdev); + } +} + +static void vu_scmi_event(void *opaque, QEMUChrEvent event) +{ + DeviceState *dev = opaque; + + switch (event) { + case CHR_EVENT_OPENED: + vu_scmi_connect(dev); + break; + case CHR_EVENT_CLOSED: + vu_scmi_disconnect(dev); + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } +} + +static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserSCMI *scmi) +{ + virtio_delete_queue(scmi->cmd_vq); + virtio_delete_queue(scmi->event_vq); + g_free(scmi->vhost_dev.vqs); + virtio_cleanup(vdev); + vhost_user_cleanup(&scmi->vhost_user); +} + +static void vu_scmi_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCMI *scmi = VHOST_USER_SCMI(dev); + int ret; + + if (!scmi->chardev.chr) { + error_setg(errp, "vhost-user-scmi: chardev is mandatory"); + return; + } + + vdev->host_features |= (1ULL << VIRTIO_SCMI_F_P2A_CHANNELS); + + if (!vhost_user_init(&scmi->vhost_user, &scmi->chardev, errp)) { + return; + } + + virtio_init(vdev, VIRTIO_ID_SCMI, 0); + + scmi->cmd_vq = virtio_add_queue(vdev, 256, vu_scmi_handle_output); + scmi->event_vq = virtio_add_queue(vdev, 256, vu_scmi_handle_output); + scmi->vhost_dev.nvqs = 2; + scmi->vhost_dev.vqs = g_new0(struct vhost_virtqueue, scmi->vhost_dev.nvqs); + + ret = vhost_dev_init(&scmi->vhost_dev, &scmi->vhost_user, + VHOST_BACKEND_TYPE_USER, 0, errp); + if (ret < 0) { + error_setg_errno(errp, -ret, + "vhost-user-scmi: vhost_dev_init() failed"); + do_vhost_user_cleanup(vdev, scmi); + return; + } + + qemu_chr_fe_set_handlers(&scmi->chardev, NULL, NULL, vu_scmi_event, NULL, + dev, NULL, true); + + return; +} + +static void vu_scmi_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserSCMI *scmi = VHOST_USER_SCMI(dev); + + vu_scmi_set_status(vdev, 0); + vhost_dev_cleanup(&scmi->vhost_dev); + do_vhost_user_cleanup(vdev, scmi); +} + +static const VMStateDescription vu_scmi_vmstate = { + .name = "vhost-user-scmi", + .unmigratable = 1, +}; + +static Property vu_scmi_properties[] = { + DEFINE_PROP_CHR("chardev", VHostUserSCMI, chardev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vu_scmi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + device_class_set_props(dc, vu_scmi_properties); + dc->vmsd = &vu_scmi_vmstate; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + vdc->realize = vu_scmi_device_realize; + vdc->unrealize = vu_scmi_device_unrealize; + vdc->get_features = vu_scmi_get_features; + vdc->set_status = vu_scmi_set_status; + vdc->guest_notifier_mask = vu_scmi_guest_notifier_mask; + vdc->guest_notifier_pending = vu_scmi_guest_notifier_pending; +} + +static const TypeInfo vu_scmi_info = { + .name = TYPE_VHOST_USER_SCMI, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VHostUserSCMI), + .class_init = vu_scmi_class_init, +}; + +static void vu_scmi_register_types(void) +{ + type_register_static(&vu_scmi_info); +} + +type_init(vu_scmi_register_types) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index c4e0cbd702..8dcf049d42 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -367,7 +367,7 @@ static int process_message_reply(struct vhost_dev *dev, return msg_reply.payload.u64 ? -EIO : 0; } -static bool vhost_user_one_time_request(VhostUserRequest request) +static bool vhost_user_per_device_request(VhostUserRequest request) { switch (request) { case VHOST_USER_SET_OWNER: @@ -375,6 +375,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request) case VHOST_USER_SET_MEM_TABLE: case VHOST_USER_GET_QUEUE_NUM: case VHOST_USER_NET_SET_MTU: + case VHOST_USER_RESET_DEVICE: case VHOST_USER_ADD_MEM_REG: case VHOST_USER_REM_MEM_REG: return true; @@ -392,11 +393,17 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, int ret, size = VHOST_USER_HDR_SIZE + msg->hdr.size; /* - * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, - * we just need send it once in the first time. For later such - * request, we just ignore it. + * Some devices, like virtio-scsi, are implemented as a single vhost_dev, + * while others, like virtio-net, contain multiple vhost_devs. For + * operations such as configuring device memory mappings or issuing device + * resets, which affect the whole device instead of individual VQs, + * vhost-user messages should only be sent once. + * + * Devices with multiple vhost_devs are given an associated dev->vq_index + * so per_device requests are only sent if vq_index is 0. */ - if (vhost_user_one_time_request(msg->hdr.request) && dev->vq_index != 0) { + if (vhost_user_per_device_request(msg->hdr.request) + && dev->vq_index != 0) { msg->hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK; return 0; } @@ -1256,7 +1263,7 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) .hdr.flags = VHOST_USER_VERSION, }; - if (vhost_user_one_time_request(request) && dev->vq_index != 0) { + if (vhost_user_per_device_request(request) && dev->vq_index != 0) { return 0; } diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 3c575a9a6e..42f2a4bae9 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -323,7 +323,9 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != (section->offset_within_region & ~TARGET_PAGE_MASK))) { - error_report("%s received unaligned region", __func__); + trace_vhost_vdpa_listener_region_add_unaligned(v, section->mr->name, + section->offset_within_address_space & ~TARGET_PAGE_MASK, + section->offset_within_region & ~TARGET_PAGE_MASK); return; } @@ -405,7 +407,9 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != (section->offset_within_region & ~TARGET_PAGE_MASK))) { - error_report("%s received unaligned region", __func__); + trace_vhost_vdpa_listener_region_del_unaligned(v, section->mr->name, + section->offset_within_address_space & ~TARGET_PAGE_MASK, + section->offset_within_region & ~TARGET_PAGE_MASK); return; } @@ -859,7 +863,7 @@ static int vhost_vdpa_reset_device(struct vhost_dev *dev) uint8_t status = 0; ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); - trace_vhost_vdpa_reset_device(dev, status); + trace_vhost_vdpa_reset_device(dev); v->suspended = false; return ret; } diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index 321262f6b3..12ea87d7a7 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -129,7 +129,7 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ @@ -146,7 +146,7 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 82394331bf..abf0d03c8d 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -780,7 +780,6 @@ static void vhost_iommu_region_add(MemoryListener *listener, Int128 end; int iommu_idx; IOMMUMemoryRegion *iommu_mr; - int ret; if (!memory_region_is_iommu(section->mr)) { return; @@ -795,7 +794,9 @@ static void vhost_iommu_region_add(MemoryListener *listener, iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, MEMTXATTRS_UNSPECIFIED); iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify, - IOMMU_NOTIFIER_DEVIOTLB_UNMAP, + dev->vdev->device_iotlb_enabled ? + IOMMU_NOTIFIER_DEVIOTLB_UNMAP : + IOMMU_NOTIFIER_UNMAP, section->offset_within_region, int128_get64(end), iommu_idx); @@ -803,16 +804,8 @@ static void vhost_iommu_region_add(MemoryListener *listener, iommu->iommu_offset = section->offset_within_address_space - section->offset_within_region; iommu->hdev = dev; - ret = memory_region_register_iommu_notifier(section->mr, &iommu->n, NULL); - if (ret) { - /* - * Some vIOMMUs do not support dev-iotlb yet. If so, try to use the - * UNMAP legacy message - */ - iommu->n.notifier_flags = IOMMU_NOTIFIER_UNMAP; - memory_region_register_iommu_notifier(section->mr, &iommu->n, - &error_fatal); - } + memory_region_register_iommu_notifier(section->mr, &iommu->n, + &error_fatal); QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next); /* TODO: can replay help performance here? */ } @@ -840,6 +833,27 @@ static void vhost_iommu_region_del(MemoryListener *listener, } } +void vhost_toggle_device_iotlb(VirtIODevice *vdev) +{ + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + struct vhost_dev *dev; + struct vhost_iommu *iommu; + + if (vdev->vhost_started) { + dev = vdc->get_vhost(vdev); + } else { + return; + } + + QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) { + memory_region_unregister_iommu_notifier(iommu->mr, &iommu->n); + iommu->n.notifier_flags = vdev->device_iotlb_enabled ? + IOMMU_NOTIFIER_DEVIOTLB_UNMAP : IOMMU_NOTIFIER_UNMAP; + memory_region_register_iommu_notifier(iommu->mr, &iommu->n, + &error_fatal); + } +} + static int vhost_virtqueue_set_addr(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx, bool enable_log) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index a6d7e1e8ec..44faf5a522 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -1210,7 +1210,7 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ @@ -1229,7 +1229,7 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) /* * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 - * as the Marco of configure interrupt's IDX, If this driver does not + * as the macro of configure interrupt's IDX, If this driver does not * support, the function will return */ diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 1bbad23f4a..201127c488 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -25,6 +25,7 @@ #include "hw/virtio/virtio.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" +#include "sysemu/sysemu.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "trace.h" @@ -1100,29 +1101,24 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr, new_mask); if ((cur_mask & new_mask) == 0) { - error_setg(errp, "virtio-iommu page mask 0x%"PRIx64 - " is incompatible with mask 0x%"PRIx64, cur_mask, new_mask); + error_setg(errp, "virtio-iommu %s reports a page size mask 0x%"PRIx64 + " incompatible with currently supported mask 0x%"PRIx64, + mr->parent_obj.name, new_mask, cur_mask); return -1; } /* - * After the machine is finalized, we can't change the mask anymore. If by + * Once the granule is frozen we can't change the mask anymore. If by * chance the hotplugged device supports the same granule, we can still - * accept it. Having a different masks is possible but the guest will use - * sub-optimal block sizes, so warn about it. + * accept it. */ - if (phase_check(PHASE_MACHINE_READY)) { - int new_granule = ctz64(new_mask); + if (s->granule_frozen) { int cur_granule = ctz64(cur_mask); - if (new_granule != cur_granule) { - error_setg(errp, "virtio-iommu page mask 0x%"PRIx64 - " is incompatible with mask 0x%"PRIx64, cur_mask, - new_mask); + if (!(BIT(cur_granule) & new_mask)) { + error_setg(errp, "virtio-iommu %s does not support frozen granule 0x%llx", + mr->parent_obj.name, BIT_ULL(cur_granule)); return -1; - } else if (new_mask != cur_mask) { - warn_report("virtio-iommu page mask 0x%"PRIx64 - " does not match 0x%"PRIx64, cur_mask, new_mask); } return 0; } @@ -1146,6 +1142,28 @@ static void virtio_iommu_system_reset(void *opaque) } +static void virtio_iommu_freeze_granule(Notifier *notifier, void *data) +{ + VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done); + int granule; + + if (likely(s->config.bypass)) { + /* + * Transient IOMMU MR enable to collect page_size_mask requirements + * through memory_region_iommu_set_page_size_mask() called by + * VFIO region_add() callback + */ + s->config.bypass = false; + virtio_iommu_switch_address_space_all(s); + /* restore default */ + s->config.bypass = true; + virtio_iommu_switch_address_space_all(s); + } + s->granule_frozen = true; + granule = ctz64(s->config.page_size_mask); + trace_virtio_iommu_freeze_granule(BIT(granule)); +} + static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -1189,6 +1207,9 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!"); } + s->machine_done.notify = virtio_iommu_freeze_granule; + qemu_add_machine_init_done_notifier(&s->machine_done); + qemu_register_reset(virtio_iommu_system_reset, s); } @@ -1198,6 +1219,7 @@ static void virtio_iommu_device_unrealize(DeviceState *dev) VirtIOIOMMU *s = VIRTIO_IOMMU(dev); qemu_unregister_reset(virtio_iommu_system_reset, s); + qemu_remove_machine_init_done_notifier(&s->machine_done); g_hash_table_destroy(s->as_by_busptr); if (s->domains) { |