virtio: allow finalize_features to fail
This will make it easy for transports to validate features and return failure. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
ce15408f35
commit
5c609a5ef0
@ -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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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 @@ out_free:
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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);
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|||||||
|
|
||||||
/* 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 @@
|
|||||||
* 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 {
|
|||||||
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);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user