virtio,pc,pci: features, fixes, cleanups

i286 acpi speedup by precomputing _PRT by Ricardo Ribalda
 vhost_net speedup by using MR transactions by Zuo Boqun
 ich9 gained support for periodic and swsmi timer by Dominic Prinz
 
 Fixes, cleanups all over the place.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmbhoCUPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRptpUH/iR5AmJFpvAItqlPOvJiYDEch46C73tyrSws
 Kk/1EbGSL7mFFD5sfdSSV4Rw8CQBsmM/Dt5VDkJKsWnOLjkBQ2CYH0MYHktnrKcJ
 LlSk32HnY5p1DsXnJhgm5M7St8T3mV/oFdJCJAFgCmpx5uT8IRLrKETN8+30OaiY
 xo35xAKOAS296+xsWeVubKkMq7H4y2tdZLE/22gb8rlA8d96BJIeVLQ3y3IjeUPR
 24q6c7zpObzGhYNZ/PzAKOn+YcVsV/lLAzKRZJTzTUPyG24BcjJTyyr/zNSYAgfk
 lLXzIZID3GThBmrCAiDZ1z6sfo3MRg2wNS/FBXtK6fPIuFxed+8=
 =ySRy
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pc,pci: features, fixes, cleanups

i286 acpi speedup by precomputing _PRT by Ricardo Ribalda
vhost_net speedup by using MR transactions by Zuo Boqun
ich9 gained support for periodic and swsmi timer by Dominic Prinz

Fixes, cleanups all over the place.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmbhoCUPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRptpUH/iR5AmJFpvAItqlPOvJiYDEch46C73tyrSws
# Kk/1EbGSL7mFFD5sfdSSV4Rw8CQBsmM/Dt5VDkJKsWnOLjkBQ2CYH0MYHktnrKcJ
# LlSk32HnY5p1DsXnJhgm5M7St8T3mV/oFdJCJAFgCmpx5uT8IRLrKETN8+30OaiY
# xo35xAKOAS296+xsWeVubKkMq7H4y2tdZLE/22gb8rlA8d96BJIeVLQ3y3IjeUPR
# 24q6c7zpObzGhYNZ/PzAKOn+YcVsV/lLAzKRZJTzTUPyG24BcjJTyyr/zNSYAgfk
# lLXzIZID3GThBmrCAiDZ1z6sfo3MRg2wNS/FBXtK6fPIuFxed+8=
# =ySRy
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 11 Sep 2024 14:50:29 BST
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu:
  hw/acpi/ich9: Add periodic and swsmi timer
  virtio-mem: don't warn about THP sizes on a kernel without THP support
  hw/audio/virtio-sound: fix heap buffer overflow
  hw/cxl: fix physical address field in get scan media results output
  virtio-pci: Add lookup subregion of VirtIOPCIRegion MR
  vhost_net: configure all host notifiers in a single MR transaction
  tests/acpi: pc: update golden masters for DSDT
  hw/i386/acpi-build: Return a pre-computed _PRT table
  tests/acpi: pc: allow DSDT acpi table changes
  intel_iommu: Make PASID-cache and PIOTLB type invalid in legacy mode
  intel_iommu: Fix invalidation descriptor type field
  virtio: rename virtio_split_packed_update_used_idx
  hw/pci/pci-hmp-cmds: Avoid displaying bogus size in 'info pci'
  pci: don't skip function 0 occupancy verification for devfn auto assign
  hw/isa/vt82c686.c: Embed i8259 irq in device state instead of allocating
  hw: Move declaration of IRQState to header and add init function
  virtio: Always reset vhost devices
  virtio: Allow .get_vhost() without vhost_started

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-09-12 16:17:26 +01:00
commit 3baa3c9d62
44 changed files with 473 additions and 202 deletions

View File

@ -35,6 +35,7 @@
#include "sysemu/runstate.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9_tco.h"
#include "hw/acpi/ich9_timer.h"
#include "hw/southbridge/ich9.h"
#include "hw/mem/pc-dimm.h"
@ -108,6 +109,18 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
}
pm->smi_en &= ~pm->smi_en_wmask;
pm->smi_en |= (val & pm->smi_en_wmask);
if (pm->swsmi_timer_enabled) {
ich9_pm_update_swsmi_timer(pm, pm->smi_en &
ICH9_PMIO_SMI_EN_SWSMI_EN);
}
if (pm->periodic_timer_enabled) {
ich9_pm_update_periodic_timer(pm, pm->smi_en &
ICH9_PMIO_SMI_EN_PERIODIC_EN);
}
break;
case 4:
pm->smi_sts &= ~pm->smi_sts_wmask;
pm->smi_sts |= (val & pm->smi_sts_wmask);
break;
}
}
@ -286,6 +299,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
{
pm->smi_sts_wmask = 0;
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
memory_region_set_enabled(&pm->io, false);
memory_region_add_subregion(pci_address_space_io(lpc_pci),
@ -305,6 +320,14 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
"acpi-smi", 8);
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
if (pm->swsmi_timer_enabled) {
ich9_pm_swsmi_timer_init(pm);
}
if (pm->periodic_timer_enabled) {
ich9_pm_periodic_timer_init(pm);
}
if (pm->enable_tco) {
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
}

93
hw/acpi/ich9_timer.c Normal file
View File

@ -0,0 +1,93 @@
/*
* QEMU ICH9 Timer emulation
*
* Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/core/cpu.h"
#include "hw/pci/pci.h"
#include "hw/southbridge/ich9.h"
#include "qemu/timer.h"
#include "hw/acpi/ich9_timer.h"
void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable)
{
uint16_t swsmi_rate_sel;
int64_t expire_time;
ICH9LPCState *lpc;
if (enable) {
lpc = container_of(pm, ICH9LPCState, pm);
swsmi_rate_sel =
(pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_3) & 0xc0) >> 6;
if (swsmi_rate_sel == 0) {
expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1500000LL;
} else {
expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
8 * (1 << swsmi_rate_sel) * 1000000LL;
}
timer_mod(pm->swsmi_timer, expire_time);
} else {
timer_del(pm->swsmi_timer);
}
}
static void ich9_pm_swsmi_timer_expired(void *opaque)
{
ICH9LPCPMRegs *pm = opaque;
pm->smi_sts |= ICH9_PMIO_SMI_STS_SWSMI_STS;
ich9_generate_smi();
ich9_pm_update_swsmi_timer(pm, pm->smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
}
void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm)
{
pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_SWSMI_STS;
pm->swsmi_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_swsmi_timer_expired, pm);
}
void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable)
{
uint16_t per_smi_sel;
int64_t expire_time;
ICH9LPCState *lpc;
if (enable) {
lpc = container_of(pm, ICH9LPCState, pm);
per_smi_sel = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1) & 3;
expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
8 * (1 << (3 - per_smi_sel)) * NANOSECONDS_PER_SECOND;
timer_mod(pm->periodic_timer, expire_time);
} else {
timer_del(pm->periodic_timer);
}
}
static void ich9_pm_periodic_timer_expired(void *opaque)
{
ICH9LPCPMRegs *pm = opaque;
pm->smi_sts = ICH9_PMIO_SMI_STS_PERIODIC_STS;
ich9_generate_smi();
ich9_pm_update_periodic_timer(pm,
pm->smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
}
void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm)
{
pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_PERIODIC_STS;
pm->periodic_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_periodic_timer_expired, pm);
}

View File

@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))

View File

@ -41,7 +41,6 @@ asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)"
#virtio-snd.c
virtio_snd_get_config(void *vdev, uint32_t jacks, uint32_t streams, uint32_t chmaps) "snd %p: get_config jacks=%"PRIu32" streams=%"PRIu32" chmaps=%"PRIu32""
virtio_snd_set_config(void *vdev, uint32_t jacks, uint32_t new_jacks, uint32_t streams, uint32_t new_streams, uint32_t chmaps, uint32_t new_chmaps) "snd %p: set_config jacks from %"PRIu32"->%"PRIu32", streams from %"PRIu32"->%"PRIu32", chmaps from %"PRIu32"->%"PRIu32
virtio_snd_get_features(void *vdev, uint64_t features) "snd %p: get_features 0x%"PRIx64
virtio_snd_vm_state_running(void) "vm state running"
virtio_snd_vm_state_stopped(void) "vm state stopped"

View File

@ -107,29 +107,6 @@ virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
}
static void
virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
{
VirtIOSound *s = VIRTIO_SND(vdev);
const virtio_snd_config *sndconfig =
(const virtio_snd_config *)config;
trace_virtio_snd_set_config(vdev,
s->snd_conf.jacks,
sndconfig->jacks,
s->snd_conf.streams,
sndconfig->streams,
s->snd_conf.chmaps,
sndconfig->chmaps);
memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
le32_to_cpus(&s->snd_conf.jacks);
le32_to_cpus(&s->snd_conf.streams);
le32_to_cpus(&s->snd_conf.chmaps);
}
static void
virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer)
{
@ -1400,7 +1377,6 @@ static void virtio_snd_class_init(ObjectClass *klass, void *data)
vdc->realize = virtio_snd_realize;
vdc->unrealize = virtio_snd_unrealize;
vdc->get_config = virtio_snd_get_config;
vdc->set_config = virtio_snd_set_config;
vdc->get_features = get_features;
vdc->reset = virtio_snd_reset;
vdc->legacy_features = 0;

View File

@ -26,16 +26,6 @@
#include "hw/irq.h"
#include "qom/object.h"
OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
struct IRQState {
Object parent_obj;
qemu_irq_handler handler;
void *opaque;
int n;
};
void qemu_set_irq(qemu_irq irq, int level)
{
if (!irq)
@ -44,6 +34,15 @@ void qemu_set_irq(qemu_irq irq, int level)
irq->handler(irq->opaque, irq->n, level);
}
void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
int n)
{
object_initialize(irq, sizeof(*irq), TYPE_IRQ);
irq->handler = handler;
irq->opaque = opaque;
irq->n = n;
}
qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
void *opaque, int n)
{
@ -69,10 +68,8 @@ qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
{
IRQState *irq;
irq = IRQ(object_new(TYPE_IRQ));
irq->handler = handler;
irq->opaque = opaque;
irq->n = n;
irq = g_new(IRQState, 1);
qemu_init_irq(irq, handler, opaque, n);
return irq;
}

View File

@ -2076,7 +2076,7 @@ static CXLRetCode cmd_media_get_scan_media_results(const struct cxl_cmd *cmd,
start = ROUND_DOWN(ent->start, 64ull);
stop = ROUND_DOWN(ent->start, 64ull) + ent->length;
stq_le_p(&out->records[i].addr, start | (ent->type & 0x7));
stq_le_p(&out->records[i].addr, start);
stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE);
i++;

View File

@ -642,7 +642,7 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
{
VhostUserGPU *g = VHOST_USER_GPU(vdev);
return &g->vhost->dev;
return g->vhost ? &g->vhost->dev : NULL;
}
static Property vhost_user_gpu_properties[] = {

View File

@ -724,120 +724,44 @@ static Aml *aml_pci_pdsm(void)
return method;
}
/**
* build_prt_entry:
* @link_name: link name for PCI route entry
*
* build AML package containing a PCI route entry for @link_name
*/
static Aml *build_prt_entry(const char *link_name)
{
Aml *a_zero = aml_int(0);
Aml *pkg = aml_package(4);
aml_append(pkg, a_zero);
aml_append(pkg, a_zero);
aml_append(pkg, aml_name("%s", link_name));
aml_append(pkg, a_zero);
return pkg;
}
/*
* initialize_route - Initialize the interrupt routing rule
* through a specific LINK:
* if (lnk_idx == idx)
* route using link 'link_name'
*/
static Aml *initialize_route(Aml *route, const char *link_name,
Aml *lnk_idx, int idx)
{
Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx)));
Aml *pkg = build_prt_entry(link_name);
aml_append(if_ctx, aml_store(pkg, route));
return if_ctx;
}
/*
* build_prt - Define interrupt rounting rules
* build_prt - Define interrupt routing rules
*
* Returns an array of 128 routes, one for each device,
* based on device location.
* The main goal is to equally distribute the interrupts
* over the 4 existing ACPI links (works only for i440fx).
* The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]".
* The hash function is: (slot + pin) & 3 -> "LNK[D|A|B|C]".
*
*/
static Aml *build_prt(bool is_pci0_prt)
{
Aml *method, *while_ctx, *pin, *res;
const int nroutes = 128;
Aml *rt_pkg, *method;
int pin;
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
res = aml_local(0);
pin = aml_local(1);
aml_append(method, aml_store(aml_package(128), res));
aml_append(method, aml_store(aml_int(0), pin));
rt_pkg = aml_varpackage(nroutes);
/* while (pin < 128) */
while_ctx = aml_while(aml_lless(pin, aml_int(128)));
{
Aml *slot = aml_local(2);
Aml *lnk_idx = aml_local(3);
Aml *route = aml_local(4);
for (pin = 0; pin < nroutes; pin++) {
Aml *pkg = aml_package(4);
int slot = pin >> 2;
/* slot = pin >> 2 */
aml_append(while_ctx,
aml_store(aml_shiftright(pin, aml_int(2), NULL), slot));
/* lnk_idx = (slot + pin) & 3 */
aml_append(while_ctx,
aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL),
lnk_idx));
/* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */
aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0));
if (is_pci0_prt) {
Aml *if_device_1, *if_pin_4, *else_pin_4;
/* device 1 is the power-management device, needs SCI */
if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1)));
{
if_pin_4 = aml_if(aml_equal(pin, aml_int(4)));
{
aml_append(if_pin_4,
aml_store(build_prt_entry("LNKS"), route));
}
aml_append(if_device_1, if_pin_4);
else_pin_4 = aml_else();
{
aml_append(else_pin_4,
aml_store(build_prt_entry("LNKA"), route));
}
aml_append(if_device_1, else_pin_4);
}
aml_append(while_ctx, if_device_1);
aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
aml_append(pkg, aml_int(pin & 3));
/* device 1 is the power-management device, needs SCI */
if (is_pci0_prt && pin == 4) {
aml_append(pkg, aml_name("%s", "LNKS"));
} else {
aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1));
static const char link_name[][5] = {"LNKD", "LNKA", "LNKB", "LNKC"};
int hash = (slot + pin) & 3;
aml_append(pkg, aml_name("%s", link_name[hash]));
}
aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2));
aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3));
/* route[0] = 0x[slot]FFFF */
aml_append(while_ctx,
aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF),
NULL),
aml_index(route, aml_int(0))));
/* route[1] = pin & 3 */
aml_append(while_ctx,
aml_store(aml_and(pin, aml_int(3), NULL),
aml_index(route, aml_int(1))));
/* res[pin] = route */
aml_append(while_ctx, aml_store(route, aml_index(res, pin)));
/* pin++ */
aml_append(while_ctx, aml_increment(pin));
aml_append(pkg, aml_int(0));
aml_append(rt_pkg, pkg);
}
aml_append(method, while_ctx);
/* return res*/
aml_append(method, aml_return(res));
aml_append(method, aml_return(rt_pkg));
return method;
}

View File

@ -2744,7 +2744,7 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
return false;
}
desc_type = inv_desc.lo & VTD_INV_DESC_TYPE;
desc_type = VTD_INV_DESC_TYPE(inv_desc.lo);
/* FIXME: should update at first or at last? */
s->iq_last_desc_type = desc_type;
@ -2763,17 +2763,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
/*
* TODO: the entity of below two cases will be implemented in future series.
* To make guest (which integrates scalable mode support patch set in
* iommu driver) work, just return true is enough so far.
*/
case VTD_INV_DESC_PC:
break;
case VTD_INV_DESC_PIOTLB:
break;
case VTD_INV_DESC_WAIT:
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
if (!vtd_process_wait_desc(s, &inv_desc)) {
@ -2795,6 +2784,17 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
/*
* TODO: the entity of below two cases will be implemented in future series.
* To make guest (which integrates scalable mode support patch set in
* iommu driver) work, just return true is enough so far.
*/
case VTD_INV_DESC_PC:
case VTD_INV_DESC_PIOTLB:
if (s->scalable_mode) {
break;
}
/* fallthrough */
default:
error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
" (unknown type)", __func__, inv_desc.hi,

View File

@ -356,7 +356,8 @@ union VTDInvDesc {
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
#define VTD_INV_DESC_TYPE 0xf
#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
((val) & 0xfULL))
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
#define VTD_INV_DESC_IOTLB 0x2
#define VTD_INV_DESC_DEVICE 0x3
@ -372,7 +373,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_WAIT_IF (1ULL << 4)
#define VTD_INV_DESC_WAIT_FN (1ULL << 6)
#define VTD_INV_DESC_WAIT_DATA_SHIFT 32
#define VTD_INV_DESC_WAIT_RSVD_LO 0Xffffff80ULL
#define VTD_INV_DESC_WAIT_RSVD_LO 0Xfffff180ULL
#define VTD_INV_DESC_WAIT_RSVD_HI 3ULL
/* Masks for Context-cache Invalidation Descriptor */
@ -383,7 +384,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_CC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_CC_SID(val) (((val) >> 32) & 0xffffUL)
#define VTD_INV_DESC_CC_FM(val) (((val) >> 48) & 3UL)
#define VTD_INV_DESC_CC_RSVD 0xfffc00000000ffc0ULL
#define VTD_INV_DESC_CC_RSVD 0xfffc00000000f1c0ULL
/* Masks for IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_IOTLB_G (3ULL << 4)
@ -393,7 +394,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL)
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4)
@ -406,7 +407,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1)
#define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL)
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0
/* Rsvd field masks for spte */
#define VTD_SPTE_SNP 0x800ULL

View File

@ -79,7 +79,10 @@
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
GlobalProperty pc_compat_9_1[] = {};
GlobalProperty pc_compat_9_1[] = {
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
};
const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
GlobalProperty pc_compat_9_0[] = {

View File

@ -43,6 +43,7 @@
#include "hw/southbridge/ich9.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9.h"
#include "hw/acpi/ich9_timer.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
#include "sysemu/runstate.h"
@ -531,6 +532,15 @@ ich9_lpc_pmcon_update(ICH9LPCState *lpc)
uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
uint16_t wmask;
if (lpc->pm.swsmi_timer_enabled) {
ich9_pm_update_swsmi_timer(
&lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
}
if (lpc->pm.periodic_timer_enabled) {
ich9_pm_update_periodic_timer(
&lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
}
if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
@ -826,6 +836,10 @@ static Property ich9_lpc_properties[] = {
ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT, true),
DEFINE_PROP_BIT64("x-smi-cpu-hotunplug", ICH9LPCState, smi_host_features,
ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT, true),
DEFINE_PROP_BOOL("x-smi-swsmi-timer", ICH9LPCState,
pm.swsmi_timer_enabled, true),
DEFINE_PROP_BOOL("x-smi-periodic-timer", ICH9LPCState,
pm.periodic_timer_enabled, true),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -592,6 +592,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA)
struct ViaISAState {
PCIDevice dev;
IRQState i8259_irq;
qemu_irq cpu_intr;
qemu_irq *isa_irqs_in;
uint16_t irq_state[ISA_NUM_IRQS];
@ -715,13 +717,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
ViaISAState *s = VIA_ISA(d);
DeviceState *dev = DEVICE(d);
PCIBus *pci_bus = pci_get_bus(d);
qemu_irq *isa_irq;
ISABus *isa_bus;
int i;
qdev_init_gpio_out_named(dev, &s->cpu_intr, "intr", 1);
qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS);
isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
qemu_init_irq(&s->i8259_irq, via_isa_request_i8259_irq, s, 0);
isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
errp);
@ -729,7 +730,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
return;
}
s->isa_irqs_in = i8259_init(isa_bus, *isa_irq);
s->isa_irqs_in = i8259_init(isa_bus, &s->i8259_irq);
isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(OBJECT(d), isa_bus, 0);

View File

@ -162,6 +162,135 @@ void vhost_net_save_acked_features(NetClientState *nc)
#endif
}
static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev,
NetClientState *ncs, int data_queue_pairs, int nvhosts)
{
VirtIONet *n = VIRTIO_NET(dev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
struct vhost_net *net;
struct vhost_dev *hdev;
int r, i, j;
NetClientState *peer;
/*
* Batch all the host notifiers in a single transaction to avoid
* quadratic time complexity in address_space_update_ioeventfds().
*/
memory_region_transaction_begin();
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else {
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
net = get_vhost_net(peer);
hdev = &net->dev;
for (j = 0; j < hdev->nvqs; j++) {
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
hdev->vq_index + j,
false);
if (r < 0) {
error_report("vhost %d VQ %d notifier cleanup failed: %d",
i, j, -r);
}
assert(r >= 0);
}
}
/*
* The transaction expects the ioeventfds to be open when it
* commits. Do it now, before the cleanup loop.
*/
memory_region_transaction_commit();
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else {
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
net = get_vhost_net(peer);
hdev = &net->dev;
for (j = 0; j < hdev->nvqs; j++) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus),
hdev->vq_index + j);
}
virtio_device_release_ioeventfd(dev);
}
}
static int vhost_net_enable_notifiers(VirtIODevice *dev,
NetClientState *ncs, int data_queue_pairs, int cvq)
{
VirtIONet *n = VIRTIO_NET(dev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
int nvhosts = data_queue_pairs + cvq;
struct vhost_net *net;
struct vhost_dev *hdev;
int r, i, j;
NetClientState *peer;
/*
* Batch all the host notifiers in a single transaction to avoid
* quadratic time complexity in address_space_update_ioeventfds().
*/
memory_region_transaction_begin();
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else {
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
net = get_vhost_net(peer);
hdev = &net->dev;
/*
* We will pass the notifiers to the kernel, make sure that QEMU
* doesn't interfere.
*/
r = virtio_device_grab_ioeventfd(dev);
if (r < 0) {
error_report("binding does not support host notifiers");
memory_region_transaction_commit();
goto fail_nvhosts;
}
for (j = 0; j < hdev->nvqs; j++) {
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
hdev->vq_index + j,
true);
if (r < 0) {
error_report("vhost %d VQ %d notifier binding failed: %d",
i, j, -r);
memory_region_transaction_commit();
vhost_dev_disable_notifiers_nvqs(hdev, dev, j);
goto fail_nvhosts;
}
}
}
memory_region_transaction_commit();
return 0;
fail_nvhosts:
vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i);
return r;
}
/*
* Stop processing guest IO notifications in qemu.
* Start processing them in vhost in kernel.
*/
static void vhost_net_disable_notifiers(VirtIODevice *dev,
NetClientState *ncs, int data_queue_pairs, int cvq)
{
vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs,
data_queue_pairs + cvq);
}
static int vhost_net_get_fd(NetClientState *backend)
{
switch (backend->info->type) {
@ -272,11 +401,6 @@ static int vhost_net_start_one(struct vhost_net *net,
}
}
r = vhost_dev_enable_notifiers(&net->dev, dev);
if (r < 0) {
goto fail_notifiers;
}
r = vhost_dev_start(&net->dev, dev, false);
if (r < 0) {
goto fail_start;
@ -328,8 +452,6 @@ fail:
}
vhost_dev_stop(&net->dev, dev, false);
fail_start:
vhost_dev_disable_notifiers(&net->dev, dev);
fail_notifiers:
return r;
}
@ -351,7 +473,6 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->stop) {
net->nc->info->stop(net->nc);
}
vhost_dev_disable_notifiers(&net->dev, dev);
}
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
@ -396,10 +517,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
}
}
r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq);
if (r < 0) {
error_report("Error enabling host notifiers: %d", -r);
goto err;
}
r = k->set_guest_notifiers(qbus->parent, total_notifiers, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
goto err;
goto err_host_notifiers;
}
for (i = 0; i < nvhosts; i++) {
@ -414,19 +541,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
r = vhost_set_vring_enable(peer, peer->vring_enable);
if (r < 0) {
goto err_start;
goto err_guest_notifiers;
}
}
r = vhost_net_start_one(get_vhost_net(peer), dev);
if (r < 0) {
goto err_start;
goto err_guest_notifiers;
}
}
return 0;
err_start:
err_guest_notifiers:
while (--i >= 0) {
peer = qemu_get_peer(ncs, i < data_queue_pairs ?
i : n->max_queue_pairs);
@ -437,6 +564,8 @@ err_start:
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
}
err_host_notifiers:
vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
err:
return r;
}
@ -468,6 +597,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
fflush(stderr);
}
assert(r >= 0);
vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
}
void vhost_net_cleanup(struct vhost_net *net)

View File

@ -3896,8 +3896,23 @@ static bool dev_unplug_pending(void *opaque)
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_queue(n->nic);
struct vhost_net *net = get_vhost_net(nc->peer);
NetClientState *nc;
struct vhost_net *net;
if (!n->nic) {
return NULL;
}
nc = qemu_get_queue(n->nic);
if (!nc) {
return NULL;
}
net = get_vhost_net(nc->peer);
if (!net) {
return NULL;
}
return &net->dev;
}

View File

@ -83,15 +83,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
if (!strcmp(region->value->type, "io")) {
monitor_printf(mon, "I/O at 0x%04" PRIx64
" [0x%04" PRIx64 "].\n",
addr, addr + size - 1);
if (addr != PCI_BAR_UNMAPPED) {
monitor_printf(mon, "I/O at 0x%04" PRIx64
" [0x%04" PRIx64 "]\n",
addr, addr + size - 1);
} else {
monitor_printf(mon, "I/O (not mapped)\n");
}
} else {
monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
" [0x%08" PRIx64 "].\n",
region->value->mem_type_64 ? 64 : 32,
region->value->prefetch ? " prefetchable" : "",
addr, addr + size - 1);
if (addr != PCI_BAR_UNMAPPED) {
monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
" [0x%08" PRIx64 "]\n",
region->value->mem_type_64 ? 64 : 32,
region->value->prefetch ? " prefetchable" : "",
addr, addr + size - 1);
} else {
monitor_printf(mon, "%d bit%s memory (not mapped)\n",
region->value->mem_type_64 ? 64 : 32,
region->value->prefetch ? " prefetchable" : "");
}
}
}

View File

@ -1181,14 +1181,15 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
bus->devices[devfn]->name, bus->devices[devfn]->qdev.id);
return NULL;
} /*
* Populating function 0 triggers a scan from the guest that
* exposes other non-zero functions. Hence we need to ensure that
* function 0 wasn't added yet.
*/
else if (dev->hotplugged &&
!pci_is_vf(pci_dev) &&
pci_get_function_0(pci_dev)) {
}
/*
* Populating function 0 triggers a scan from the guest that
* exposes other non-zero functions. Hence we need to ensure that
* function 0 wasn't added yet.
*/
if (dev->hotplugged && !pci_is_vf(pci_dev) &&
pci_get_function_0(pci_dev)) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" new func %s cannot be exposed to guest.",
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),

View File

@ -1682,9 +1682,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
memset(hdev, 0, sizeof(struct vhost_dev));
}
static void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
VirtIODevice *vdev,
unsigned int nvqs)
void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
VirtIODevice *vdev,
unsigned int nvqs)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
int i, r;

View File

@ -1247,9 +1247,21 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
CryptoDevBackend *b = vcrypto->cryptodev;
CryptoDevBackendClient *cc = b->conf.peers.ccs[0];
CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0);
CryptoDevBackend *b;
CryptoDevBackendClient *cc;
CryptoDevBackendVhost *vhost_crypto;
b = vcrypto->cryptodev;
if (!b) {
return NULL;
}
cc = b->conf.peers.ccs[0];
vhost_crypto = cryptodev_get_vhost(cc, b, 0);
if (!vhost_crypto) {
return NULL;
}
return &vhost_crypto->dev;
}

View File

@ -88,6 +88,7 @@ static uint32_t virtio_mem_default_thp_size(void)
static uint32_t thp_size;
#define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
#define HPAGE_PATH "/sys/kernel/mm/transparent_hugepage/"
static uint32_t virtio_mem_thp_size(void)
{
gchar *content = NULL;
@ -98,6 +99,12 @@ static uint32_t virtio_mem_thp_size(void)
return thp_size;
}
/* No THP -> no restrictions. */
if (!g_file_test(HPAGE_PATH, G_FILE_TEST_EXISTS)) {
thp_size = VIRTIO_MEM_MIN_BLOCK_SIZE;
return thp_size;
}
/*
* Try to probe the actual THP size, fallback to (sane but eventually
* incorrect) default sizes.

View File

@ -615,8 +615,12 @@ static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy,
reg = &proxy->regs[i];
if (*off >= reg->offset &&
*off + len <= reg->offset + reg->size) {
*off -= reg->offset;
return &reg->mr;
MemoryRegionSection mrs = memory_region_find(&reg->mr,
*off - reg->offset, len);
assert(mrs.mr);
*off = mrs.offset_within_region;
memory_region_unref(mrs.mr);
return mrs.mr;
}
}

View File

@ -2331,8 +2331,12 @@ void virtio_reset(void *opaque)
vdev->device_endian = virtio_default_endian();
}
if (vdev->vhost_started && k->get_vhost) {
vhost_reset_device(k->get_vhost(vdev));
if (k->get_vhost) {
struct vhost_dev *hdev = k->get_vhost(vdev);
/* Only reset when vhost back-end is connected */
if (hdev && hdev->vhost_ops) {
vhost_reset_device(hdev);
}
}
if (k->reset) {
@ -3665,7 +3669,7 @@ static void virtio_queue_packed_update_used_idx(VirtIODevice *vdev, int n)
return;
}
static void virtio_split_packed_update_used_idx(VirtIODevice *vdev, int n)
static void virtio_queue_split_update_used_idx(VirtIODevice *vdev, int n)
{
RCU_READ_LOCK_GUARD();
if (vdev->vq[n].vring.desc) {
@ -3678,7 +3682,7 @@ void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
return virtio_queue_packed_update_used_idx(vdev, n);
} else {
return virtio_split_packed_update_used_idx(vdev, n);
return virtio_queue_split_update_used_idx(vdev, n);
}
}

View File

@ -46,6 +46,7 @@ typedef struct ICH9LPCPMRegs {
uint32_t smi_en;
uint32_t smi_en_wmask;
uint32_t smi_sts;
uint32_t smi_sts_wmask;
qemu_irq irq; /* SCI */
@ -68,6 +69,11 @@ typedef struct ICH9LPCPMRegs {
bool smm_compat;
bool enable_tco;
TCOIORegs tco_regs;
bool swsmi_timer_enabled;
bool periodic_timer_enabled;
QEMUTimer *swsmi_timer;
QEMUTimer *periodic_timer;
} ICH9LPCPMRegs;
#define ACPI_PM_PROP_TCO_ENABLED "enable_tco"

View File

@ -0,0 +1,23 @@
/*
* QEMU ICH9 Timer emulation
*
* Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_ACPI_ICH9_TIMER_H
#define HW_ACPI_ICH9_TIMER_H
#include "hw/acpi/ich9.h"
void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable);
void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm);
void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable);
void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm);
#endif

View File

@ -1,9 +1,20 @@
#ifndef QEMU_IRQ_H
#define QEMU_IRQ_H
#include "qom/object.h"
/* Generic IRQ/GPIO pin infrastructure. */
#define TYPE_IRQ "irq"
OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
struct IRQState {
Object parent_obj;
qemu_irq_handler handler;
void *opaque;
int n;
};
void qemu_set_irq(qemu_irq irq, int level);
@ -23,6 +34,13 @@ static inline void qemu_irq_pulse(qemu_irq irq)
qemu_set_irq(irq, 0);
}
/*
* Init a single IRQ. The irq is assigned with a handler, an opaque data
* and the interrupt number.
*/
void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
int n);
/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and
* opaque data.
*/

View File

@ -196,8 +196,12 @@ struct ICH9LPCState {
#define ICH9_PMIO_GPE0_LEN 16
#define ICH9_PMIO_SMI_EN 0x30
#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5)
#define ICH9_PMIO_SMI_EN_SWSMI_EN (1 << 6)
#define ICH9_PMIO_SMI_EN_TCO_EN (1 << 13)
#define ICH9_PMIO_SMI_EN_PERIODIC_EN (1 << 14)
#define ICH9_PMIO_SMI_STS 0x34
#define ICH9_PMIO_SMI_STS_SWSMI_STS (1 << 6)
#define ICH9_PMIO_SMI_STS_PERIODIC_STS (1 << 14)
#define ICH9_PMIO_TCO_RLD 0x60
#define ICH9_PMIO_TCO_LEN 32

View File

@ -171,6 +171,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
*/
void vhost_dev_cleanup(struct vhost_dev *hdev);
void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
VirtIODevice *vdev,
unsigned int nvqs);
/**
* vhost_dev_enable_notifiers() - enable event notifiers
* @hdev: common vhost_dev structure

View File

@ -223,6 +223,7 @@ struct VirtioDeviceClass {
int (*post_load)(VirtIODevice *vdev);
const VMStateDescription *vmsd;
bool (*primary_unplug_pending)(void *opaque);
/* May be called even when vdev->vhost_started is false */
struct vhost_dev *(*get_vhost)(VirtIODevice *vdev);
void (*toggle_device_iotlb)(VirtIODevice *vdev);
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.