virtio-pci: implement support for extended features
Extend the features configuration space to 128 bits. If the virtio device supports any extended features, allow the common read/write operation to access all of it, otherwise keep exposing only the lower 64 bits. On migration, save the 128 bit version of the features only if the upper bits are non zero. Relay on reset to clear all the feature space before load. Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Acked-by: Jason Wang <jasowang@redhat.com> Acked-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Tested-by: Lei Yang <leiyang@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <c0b81601f65b41ca8310eba8f05e2dcf3702de89.1758549625.git.pabeni@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
64a6a336f4
commit
712c79d6d3
2 changed files with 68 additions and 10 deletions
|
|
@ -109,6 +109,29 @@ static const VMStateDescription vmstate_virtio_pci_modern_queue_state = {
|
|||
}
|
||||
};
|
||||
|
||||
static bool virtio_pci_modern_state_features128_needed(void *opaque)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
uint32_t features = 0;
|
||||
int i;
|
||||
|
||||
for (i = 2; i < ARRAY_SIZE(proxy->guest_features); ++i) {
|
||||
features |= proxy->guest_features[i];
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_pci_modern_state_features128 = {
|
||||
.name = "virtio_pci/modern_state/features128",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = &virtio_pci_modern_state_features128_needed,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_SUB_ARRAY(guest_features, VirtIOPCIProxy, 2, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static bool virtio_pci_modern_state_needed(void *opaque)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
|
|
@ -116,6 +139,12 @@ static bool virtio_pci_modern_state_needed(void *opaque)
|
|||
return virtio_pci_modern(proxy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid silently breaking migration should the feature space increase
|
||||
* even more in the (far away) future
|
||||
*/
|
||||
QEMU_BUILD_BUG_ON(VIRTIO_FEATURES_NU32S != 4);
|
||||
|
||||
static const VMStateDescription vmstate_virtio_pci_modern_state_sub = {
|
||||
.name = "virtio_pci/modern_state",
|
||||
.version_id = 1,
|
||||
|
|
@ -124,11 +153,15 @@ static const VMStateDescription vmstate_virtio_pci_modern_state_sub = {
|
|||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(dfselect, VirtIOPCIProxy),
|
||||
VMSTATE_UINT32(gfselect, VirtIOPCIProxy),
|
||||
VMSTATE_UINT32_ARRAY(guest_features, VirtIOPCIProxy, 2),
|
||||
VMSTATE_UINT32_SUB_ARRAY(guest_features, VirtIOPCIProxy, 0, 2),
|
||||
VMSTATE_STRUCT_ARRAY(vqs, VirtIOPCIProxy, VIRTIO_QUEUE_MAX, 0,
|
||||
vmstate_virtio_pci_modern_queue_state,
|
||||
VirtIOPCIQueue),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription * const []) {
|
||||
&vmstate_virtio_pci_modern_state_features128,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1477,6 +1510,19 @@ int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy,
|
|||
return virtio_pci_add_mem_cap(proxy, &cap.cap);
|
||||
}
|
||||
|
||||
static int virtio_pci_select_max(const VirtIODevice *vdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = VIRTIO_FEATURES_NU64S - 1; i > 0; i--) {
|
||||
if (vdev->host_features_ex[i]) {
|
||||
return (i + 1) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
|
|
@ -1494,18 +1540,21 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
|
|||
val = proxy->dfselect;
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_DF:
|
||||
if (proxy->dfselect <= 1) {
|
||||
if (proxy->dfselect < virtio_pci_select_max(vdev)) {
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
val = (vdev->host_features & ~vdc->legacy_features) >>
|
||||
(32 * proxy->dfselect);
|
||||
val = vdev->host_features_ex[proxy->dfselect >> 1] >>
|
||||
(32 * (proxy->dfselect & 1));
|
||||
if (proxy->dfselect <= 1) {
|
||||
val &= (~vdc->legacy_features) >> (32 * proxy->dfselect);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_GFSELECT:
|
||||
val = proxy->gfselect;
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_GF:
|
||||
if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
|
||||
if (proxy->gfselect < virtio_pci_select_max(vdev)) {
|
||||
val = proxy->guest_features[proxy->gfselect];
|
||||
}
|
||||
break;
|
||||
|
|
@ -1588,11 +1637,18 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
|
|||
proxy->gfselect = val;
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_GF:
|
||||
if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
|
||||
if (proxy->gfselect < virtio_pci_select_max(vdev)) {
|
||||
uint64_t features[VIRTIO_FEATURES_NU64S];
|
||||
int i;
|
||||
|
||||
proxy->guest_features[proxy->gfselect] = val;
|
||||
virtio_set_features(vdev,
|
||||
(((uint64_t)proxy->guest_features[1]) << 32) |
|
||||
proxy->guest_features[0]);
|
||||
virtio_features_clear(features);
|
||||
for (i = 0; i < ARRAY_SIZE(proxy->guest_features); ++i) {
|
||||
uint64_t cur = proxy->guest_features[i];
|
||||
|
||||
features[i >> 1] |= cur << ((i & 1) * 32);
|
||||
}
|
||||
virtio_set_features_ex(vdev, features);
|
||||
}
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_MSIX:
|
||||
|
|
@ -2311,6 +2367,8 @@ static void virtio_pci_reset(DeviceState *qdev)
|
|||
virtio_bus_reset(bus);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
|
||||
memset(proxy->guest_features, 0, sizeof(proxy->guest_features));
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
proxy->vqs[i].enabled = 0;
|
||||
proxy->vqs[i].reset = 0;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ struct VirtIOPCIProxy {
|
|||
uint32_t nvectors;
|
||||
uint32_t dfselect;
|
||||
uint32_t gfselect;
|
||||
uint32_t guest_features[2];
|
||||
uint32_t guest_features[VIRTIO_FEATURES_NU32S];
|
||||
VirtIOPCIQueue vqs[VIRTIO_QUEUE_MAX];
|
||||
|
||||
VirtIOIRQFD *vector_irqfd;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue