diff options
| -rw-r--r-- | Documentation/lguest/lguest.c | 62 | ||||
| -rw-r--r-- | drivers/block/virtio_blk.c | 6 | ||||
| -rw-r--r-- | drivers/lguest/lguest_device.c | 14 | ||||
| -rw-r--r-- | drivers/net/virtio_net.c | 5 | ||||
| -rw-r--r-- | drivers/virtio/virtio.c | 12 | ||||
| -rw-r--r-- | drivers/virtio/virtio_ring.c | 11 | ||||
| -rw-r--r-- | include/linux/virtio.h | 5 | ||||
| -rw-r--r-- | include/linux/virtio_config.h | 4 |
8 files changed, 87 insertions, 32 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 8ff2d8bc690a..0f23d67f958f 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
| @@ -193,6 +193,13 @@ static void *_convert(struct iovec *iov, size_t size, size_t align, | |||
| 193 | #define le32_to_cpu(v32) (v32) | 193 | #define le32_to_cpu(v32) (v32) |
| 194 | #define le64_to_cpu(v64) (v64) | 194 | #define le64_to_cpu(v64) (v64) |
| 195 | 195 | ||
| 196 | /* The device virtqueue descriptors are followed by feature bitmasks. */ | ||
| 197 | static u8 *get_feature_bits(struct device *dev) | ||
| 198 | { | ||
| 199 | return (u8 *)(dev->desc + 1) | ||
| 200 | + dev->desc->num_vq * sizeof(struct lguest_vqconfig); | ||
| 201 | } | ||
| 202 | |||
| 196 | /*L:100 The Launcher code itself takes us out into userspace, that scary place | 203 | /*L:100 The Launcher code itself takes us out into userspace, that scary place |
| 197 | * where pointers run wild and free! Unfortunately, like most userspace | 204 | * where pointers run wild and free! Unfortunately, like most userspace |
| 198 | * programs, it's quite boring (which is why everyone likes to hack on the | 205 | * programs, it's quite boring (which is why everyone likes to hack on the |
| @@ -914,21 +921,58 @@ static void enable_fd(int fd, struct virtqueue *vq) | |||
| 914 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); | 921 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); |
| 915 | } | 922 | } |
| 916 | 923 | ||
| 924 | /* Resetting a device is fairly easy. */ | ||
| 925 | static void reset_device(struct device *dev) | ||
| 926 | { | ||
| 927 | struct virtqueue *vq; | ||
| 928 | |||
| 929 | verbose("Resetting device %s\n", dev->name); | ||
| 930 | /* Clear the status. */ | ||
| 931 | dev->desc->status = 0; | ||
| 932 | |||
| 933 | /* Clear any features they've acked. */ | ||
| 934 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, | ||
| 935 | dev->desc->feature_len); | ||
| 936 | |||
| 937 | /* Zero out the virtqueues. */ | ||
| 938 | for (vq = dev->vq; vq; vq = vq->next) { | ||
| 939 | memset(vq->vring.desc, 0, | ||
| 940 | vring_size(vq->config.num, getpagesize())); | ||
| 941 | vq->last_avail_idx = 0; | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 917 | /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */ | 945 | /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */ |
| 918 | static void handle_output(int fd, unsigned long addr) | 946 | static void handle_output(int fd, unsigned long addr) |
| 919 | { | 947 | { |
| 920 | struct device *i; | 948 | struct device *i; |
| 921 | struct virtqueue *vq; | 949 | struct virtqueue *vq; |
| 922 | 950 | ||
| 923 | /* Check each virtqueue. */ | 951 | /* Check each device and virtqueue. */ |
| 924 | for (i = devices.dev; i; i = i->next) { | 952 | for (i = devices.dev; i; i = i->next) { |
| 953 | /* Notifications to device descriptors reset the device. */ | ||
| 954 | if (from_guest_phys(addr) == i->desc) { | ||
| 955 | reset_device(i); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | |||
| 959 | /* Notifications to virtqueues mean output has occurred. */ | ||
| 925 | for (vq = i->vq; vq; vq = vq->next) { | 960 | for (vq = i->vq; vq; vq = vq->next) { |
| 926 | if (vq->config.pfn == addr/getpagesize()) { | 961 | if (vq->config.pfn != addr/getpagesize()) |
| 927 | verbose("Output to %s\n", vq->dev->name); | 962 | continue; |
| 928 | if (vq->handle_output) | 963 | |
| 929 | vq->handle_output(fd, vq); | 964 | /* Guest should acknowledge (and set features!) before |
| 965 | * using the device. */ | ||
| 966 | if (i->desc->status == 0) { | ||
| 967 | warnx("%s gave early output", i->name); | ||
| 930 | return; | 968 | return; |
| 931 | } | 969 | } |
| 970 | |||
| 971 | if (strcmp(vq->dev->name, "console") != 0) | ||
| 972 | verbose("Output to %s\n", vq->dev->name); | ||
| 973 | if (vq->handle_output) | ||
| 974 | vq->handle_output(fd, vq); | ||
| 975 | return; | ||
| 932 | } | 976 | } |
| 933 | } | 977 | } |
| 934 | 978 | ||
| @@ -1074,10 +1118,11 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, | |||
| 1074 | vq->vring.used->flags = VRING_USED_F_NO_NOTIFY; | 1118 | vq->vring.used->flags = VRING_USED_F_NO_NOTIFY; |
| 1075 | } | 1119 | } |
| 1076 | 1120 | ||
| 1077 | /* The virtqueue descriptors are followed by feature bytes. */ | 1121 | /* The first half of the feature bitmask is for us to advertise features. The |
| 1122 | * second half if for the Guest to accept features. */ | ||
| 1078 | static void add_feature(struct device *dev, unsigned bit) | 1123 | static void add_feature(struct device *dev, unsigned bit) |
| 1079 | { | 1124 | { |
| 1080 | u8 *features; | 1125 | u8 *features = get_feature_bits(dev); |
| 1081 | 1126 | ||
| 1082 | /* We can't extend the feature bits once we've added config bytes */ | 1127 | /* We can't extend the feature bits once we've added config bytes */ |
| 1083 | if (dev->desc->feature_len <= bit / CHAR_BIT) { | 1128 | if (dev->desc->feature_len <= bit / CHAR_BIT) { |
| @@ -1085,9 +1130,6 @@ static void add_feature(struct device *dev, unsigned bit) | |||
| 1085 | dev->desc->feature_len = (bit / CHAR_BIT) + 1; | 1130 | dev->desc->feature_len = (bit / CHAR_BIT) + 1; |
| 1086 | } | 1131 | } |
| 1087 | 1132 | ||
| 1088 | features = (u8 *)(dev->desc + 1) | ||
| 1089 | + dev->desc->num_vq * sizeof(struct lguest_vqconfig); | ||
| 1090 | |||
| 1091 | features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); | 1133 | features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); |
| 1092 | } | 1134 | } |
| 1093 | 1135 | ||
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 54a8017ad487..6143337527e7 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
| @@ -264,12 +264,16 @@ static void virtblk_remove(struct virtio_device *vdev) | |||
| 264 | struct virtio_blk *vblk = vdev->priv; | 264 | struct virtio_blk *vblk = vdev->priv; |
| 265 | int major = vblk->disk->major; | 265 | int major = vblk->disk->major; |
| 266 | 266 | ||
| 267 | /* Nothing should be pending. */ | ||
| 267 | BUG_ON(!list_empty(&vblk->reqs)); | 268 | BUG_ON(!list_empty(&vblk->reqs)); |
| 269 | |||
| 270 | /* Stop all the virtqueues. */ | ||
| 271 | vdev->config->reset(vdev); | ||
| 272 | |||
| 268 | blk_cleanup_queue(vblk->disk->queue); | 273 | blk_cleanup_queue(vblk->disk->queue); |
| 269 | put_disk(vblk->disk); | 274 | put_disk(vblk->disk); |
| 270 | unregister_blkdev(major, "virtblk"); | 275 | unregister_blkdev(major, "virtblk"); |
| 271 | mempool_destroy(vblk->pool); | 276 | mempool_destroy(vblk->pool); |
| 272 | /* There should be nothing in the queue now, so no need to shutdown */ | ||
| 273 | vdev->config->del_vq(vblk->vq); | 277 | vdev->config->del_vq(vblk->vq); |
| 274 | kfree(vblk); | 278 | kfree(vblk); |
| 275 | } | 279 | } |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index ced5b44cebce..84f85e23cca7 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
| @@ -54,7 +54,7 @@ struct lguest_device { | |||
| 54 | * | 54 | * |
| 55 | * The configuration information for a device consists of one or more | 55 | * The configuration information for a device consists of one or more |
| 56 | * virtqueues, a feature bitmaks, and some configuration bytes. The | 56 | * virtqueues, a feature bitmaks, and some configuration bytes. The |
| 57 | * configuration bytes don't really matter to us: the Launcher set them up, and | 57 | * configuration bytes don't really matter to us: the Launcher sets them up, and |
| 58 | * the driver will look at them during setup. | 58 | * the driver will look at them during setup. |
| 59 | * | 59 | * |
| 60 | * A convenient routine to return the device's virtqueue config array: | 60 | * A convenient routine to return the device's virtqueue config array: |
| @@ -139,9 +139,20 @@ static u8 lg_get_status(struct virtio_device *vdev) | |||
| 139 | 139 | ||
| 140 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 140 | static void lg_set_status(struct virtio_device *vdev, u8 status) |
| 141 | { | 141 | { |
| 142 | BUG_ON(!status); | ||
| 142 | to_lgdev(vdev)->desc->status = status; | 143 | to_lgdev(vdev)->desc->status = status; |
| 143 | } | 144 | } |
| 144 | 145 | ||
| 146 | /* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor | ||
| 147 | * address of the device. The Host will zero the status and all the | ||
| 148 | * features. */ | ||
| 149 | static void lg_reset(struct virtio_device *vdev) | ||
| 150 | { | ||
| 151 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | ||
| 152 | |||
| 153 | hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); | ||
| 154 | } | ||
| 155 | |||
| 145 | /* | 156 | /* |
| 146 | * Virtqueues | 157 | * Virtqueues |
| 147 | * | 158 | * |
| @@ -279,6 +290,7 @@ static struct virtio_config_ops lguest_config_ops = { | |||
| 279 | .set = lg_set, | 290 | .set = lg_set, |
| 280 | .get_status = lg_get_status, | 291 | .get_status = lg_get_status, |
