Commit 5c609a5e authored by Michael S. Tsirkin's avatar Michael S. Tsirkin

virtio: allow finalize_features to fail

This will make it easy for transports to validate features and return
failure.
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent ce15408f
...@@ -126,7 +126,7 @@ static void status_notify(struct virtio_device *vdev) ...@@ -126,7 +126,7 @@ static void status_notify(struct virtio_device *vdev)
* sorted out, this routine is called so we can tell the Host which features we * sorted out, this routine is called so we can tell the Host which features we
* understand and accept. * understand and accept.
*/ */
static void lg_finalize_features(struct virtio_device *vdev) static int lg_finalize_features(struct virtio_device *vdev)
{ {
unsigned int i, bits; unsigned int i, bits;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
...@@ -153,6 +153,8 @@ static void lg_finalize_features(struct virtio_device *vdev) ...@@ -153,6 +153,8 @@ static void lg_finalize_features(struct virtio_device *vdev)
/* Tell Host we've finished with this device's feature negotiation */ /* Tell Host we've finished with this device's feature negotiation */
status_notify(vdev); status_notify(vdev);
return 0;
} }
/* Once they've found a field, getting a copy of it is easy. */ /* Once they've found a field, getting a copy of it is easy. */
......
...@@ -84,7 +84,7 @@ static u64 mic_get_features(struct virtio_device *vdev) ...@@ -84,7 +84,7 @@ static u64 mic_get_features(struct virtio_device *vdev)
return features; return features;
} }
static void mic_finalize_features(struct virtio_device *vdev) static int mic_finalize_features(struct virtio_device *vdev)
{ {
unsigned int i, bits; unsigned int i, bits;
struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc; struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
...@@ -107,6 +107,8 @@ static void mic_finalize_features(struct virtio_device *vdev) ...@@ -107,6 +107,8 @@ static void mic_finalize_features(struct virtio_device *vdev)
iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)), iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)),
&out_features[i / 8]); &out_features[i / 8]);
} }
return 0;
} }
/* /*
......
...@@ -217,7 +217,7 @@ static u64 rproc_virtio_get_features(struct virtio_device *vdev) ...@@ -217,7 +217,7 @@ static u64 rproc_virtio_get_features(struct virtio_device *vdev)
return rsc->dfeatures; return rsc->dfeatures;
} }
static void rproc_virtio_finalize_features(struct virtio_device *vdev) static int rproc_virtio_finalize_features(struct virtio_device *vdev)
{ {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc; struct fw_rsc_vdev *rsc;
...@@ -235,6 +235,8 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev) ...@@ -235,6 +235,8 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev)
* to the remote processor once it is powered on. * to the remote processor once it is powered on.
*/ */
rsc->gfeatures = vdev->features; rsc->gfeatures = vdev->features;
return 0;
} }
static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
......
...@@ -93,7 +93,7 @@ static u64 kvm_get_features(struct virtio_device *vdev) ...@@ -93,7 +93,7 @@ static u64 kvm_get_features(struct virtio_device *vdev)
return features; return features;
} }
static void kvm_finalize_features(struct virtio_device *vdev) static int kvm_finalize_features(struct virtio_device *vdev)
{ {
unsigned int i, bits; unsigned int i, bits;
struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
...@@ -112,6 +112,8 @@ static void kvm_finalize_features(struct virtio_device *vdev) ...@@ -112,6 +112,8 @@ static void kvm_finalize_features(struct virtio_device *vdev)
if (__virtio_test_bit(vdev, i)) if (__virtio_test_bit(vdev, i))
out_features[i / 8] |= (1 << (i % 8)); out_features[i / 8] |= (1 << (i % 8));
} }
return 0;
} }
/* /*
......
...@@ -752,7 +752,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev) ...@@ -752,7 +752,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
return rc; return rc;
} }
static void virtio_ccw_finalize_features(struct virtio_device *vdev) static int virtio_ccw_finalize_features(struct virtio_device *vdev)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct virtio_feature_desc *features; struct virtio_feature_desc *features;
...@@ -760,7 +760,7 @@ static void virtio_ccw_finalize_features(struct virtio_device *vdev) ...@@ -760,7 +760,7 @@ static void virtio_ccw_finalize_features(struct virtio_device *vdev)
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw) if (!ccw)
return; return 0;
features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL); features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
if (!features) if (!features)
...@@ -793,6 +793,8 @@ static void virtio_ccw_finalize_features(struct virtio_device *vdev) ...@@ -793,6 +793,8 @@ static void virtio_ccw_finalize_features(struct virtio_device *vdev)
out_free: out_free:
kfree(features); kfree(features);
kfree(ccw); kfree(ccw);
return 0;
} }
static void virtio_ccw_get_config(struct virtio_device *vdev, static void virtio_ccw_get_config(struct virtio_device *vdev,
......
...@@ -212,7 +212,9 @@ static int virtio_dev_probe(struct device *_d) ...@@ -212,7 +212,9 @@ static int virtio_dev_probe(struct device *_d)
if (device_features & (1ULL << i)) if (device_features & (1ULL << i))
__virtio_set_bit(dev, i); __virtio_set_bit(dev, i);
dev->config->finalize_features(dev); err = dev->config->finalize_features(dev);
if (err)
goto err;
if (virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { if (virtio_has_feature(dev, VIRTIO_F_VERSION_1)) {
add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
...@@ -354,6 +356,7 @@ EXPORT_SYMBOL_GPL(virtio_device_freeze); ...@@ -354,6 +356,7 @@ EXPORT_SYMBOL_GPL(virtio_device_freeze);
int virtio_device_restore(struct virtio_device *dev) int virtio_device_restore(struct virtio_device *dev)
{ {
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
int ret;
/* We always start by resetting the device, in case a previous /* We always start by resetting the device, in case a previous
* driver messed it up. */ * driver messed it up. */
...@@ -373,14 +376,14 @@ int virtio_device_restore(struct virtio_device *dev) ...@@ -373,14 +376,14 @@ int virtio_device_restore(struct virtio_device *dev)
/* We have a driver! */ /* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER); add_status(dev, VIRTIO_CONFIG_S_DRIVER);
dev->config->finalize_features(dev); ret = dev->config->finalize_features(dev);
if (ret)
goto err;
if (drv->restore) { if (drv->restore) {
int ret = drv->restore(dev); ret = drv->restore(dev);
if (ret) { if (ret)
add_status(dev, VIRTIO_CONFIG_S_FAILED); goto err;
return ret;
}
} }
/* Finally, tell the device we're all set */ /* Finally, tell the device we're all set */
...@@ -389,6 +392,10 @@ int virtio_device_restore(struct virtio_device *dev) ...@@ -389,6 +392,10 @@ int virtio_device_restore(struct virtio_device *dev)
virtio_config_enable(dev); virtio_config_enable(dev);
return 0; return 0;
err:
add_status(dev, VIRTIO_CONFIG_S_FAILED);
return ret;
} }
EXPORT_SYMBOL_GPL(virtio_device_restore); EXPORT_SYMBOL_GPL(virtio_device_restore);
#endif #endif
......
...@@ -152,7 +152,7 @@ static u64 vm_get_features(struct virtio_device *vdev) ...@@ -152,7 +152,7 @@ static u64 vm_get_features(struct virtio_device *vdev)
return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES); return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES);
} }
static void vm_finalize_features(struct virtio_device *vdev) static int vm_finalize_features(struct virtio_device *vdev)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
...@@ -164,6 +164,8 @@ static void vm_finalize_features(struct virtio_device *vdev) ...@@ -164,6 +164,8 @@ static void vm_finalize_features(struct virtio_device *vdev)
writel(0, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL); writel(0, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL);
writel(vdev->features, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES); writel(vdev->features, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES);
return 0;
} }
static void vm_get(struct virtio_device *vdev, unsigned offset, static void vm_get(struct virtio_device *vdev, unsigned offset,
......
...@@ -112,7 +112,7 @@ static u64 vp_get_features(struct virtio_device *vdev) ...@@ -112,7 +112,7 @@ static u64 vp_get_features(struct virtio_device *vdev)
} }
/* virtio config->finalize_features() implementation */ /* virtio config->finalize_features() implementation */
static void vp_finalize_features(struct virtio_device *vdev) static int vp_finalize_features(struct virtio_device *vdev)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
...@@ -124,6 +124,8 @@ static void vp_finalize_features(struct virtio_device *vdev) ...@@ -124,6 +124,8 @@ static void vp_finalize_features(struct virtio_device *vdev)
/* We only support 32 feature bits. */ /* We only support 32 feature bits. */
iowrite32(vdev->features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); iowrite32(vdev->features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
return 0;
} }
/* virtio config->get() implementation */ /* virtio config->get() implementation */
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
* vdev: the virtio_device * vdev: the virtio_device
* This gives the final feature bits for the device: it can change * This gives the final feature bits for the device: it can change
* the dev->feature bits if it wants. * the dev->feature bits if it wants.
* Returns 0 on success or error status
* @bus_name: return the bus name associated with the device * @bus_name: return the bus name associated with the device
* vdev: the virtio_device * vdev: the virtio_device
* This returns a pointer to the bus name a la pci_name from which * This returns a pointer to the bus name a la pci_name from which
...@@ -68,7 +69,7 @@ struct virtio_config_ops { ...@@ -68,7 +69,7 @@ struct virtio_config_ops {
const char *names[]); const char *names[]);
void (*del_vqs)(struct virtio_device *); void (*del_vqs)(struct virtio_device *);
u64 (*get_features)(struct virtio_device *vdev); u64 (*get_features)(struct virtio_device *vdev);
void (*finalize_features)(struct virtio_device *vdev); int (*finalize_features)(struct virtio_device *vdev);
const char *(*bus_name)(struct virtio_device *vdev); const char *(*bus_name)(struct virtio_device *vdev);
int (*set_vq_affinity)(struct virtqueue *vq, int cpu); int (*set_vq_affinity)(struct virtqueue *vq, int cpu);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment