diff options
-rw-r--r-- | Documentation/lguest/lguest.c | 50 | ||||
-rw-r--r-- | drivers/lguest/lguest_device.c | 20 |
2 files changed, 48 insertions, 22 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 5cd705c3d75b..3be8ab2a886a 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
@@ -131,6 +131,9 @@ struct device | |||
131 | /* Any queues attached to this device */ | 131 | /* Any queues attached to this device */ |
132 | struct virtqueue *vq; | 132 | struct virtqueue *vq; |
133 | 133 | ||
134 | /* Handle status being finalized (ie. feature bits stable). */ | ||
135 | void (*ready)(struct device *me); | ||
136 | |||
134 | /* Device-specific data. */ | 137 | /* Device-specific data. */ |
135 | void *priv; | 138 | void *priv; |
136 | }; | 139 | }; |
@@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq) | |||
925 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); | 928 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); |
926 | } | 929 | } |
927 | 930 | ||
928 | /* When the Guest asks us to reset a device, it's is fairly easy. */ | 931 | /* When the Guest tells us they updated the status field, we handle it. */ |
929 | static void reset_device(struct device *dev) | 932 | static void update_device_status(struct device *dev) |
930 | { | 933 | { |
931 | struct virtqueue *vq; | 934 | struct virtqueue *vq; |
932 | 935 | ||
933 | verbose("Resetting device %s\n", dev->name); | 936 | /* This is a reset. */ |
934 | /* Clear the status. */ | 937 | if (dev->desc->status == 0) { |
935 | dev->desc->status = 0; | 938 | verbose("Resetting device %s\n", dev->name); |
936 | 939 | ||
937 | /* Clear any features they've acked. */ | 940 | /* Clear any features they've acked. */ |
938 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, | 941 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, |
939 | dev->desc->feature_len); | 942 | dev->desc->feature_len); |
940 | 943 | ||
941 | /* Zero out the virtqueues. */ | 944 | /* Zero out the virtqueues. */ |
942 | for (vq = dev->vq; vq; vq = vq->next) { | 945 | for (vq = dev->vq; vq; vq = vq->next) { |
943 | memset(vq->vring.desc, 0, | 946 | memset(vq->vring.desc, 0, |
944 | vring_size(vq->config.num, getpagesize())); | 947 | vring_size(vq->config.num, getpagesize())); |
945 | vq->last_avail_idx = 0; | 948 | vq->last_avail_idx = 0; |
949 | } | ||
950 | } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { | ||
951 | warnx("Device %s configuration FAILED", dev->name); | ||
952 | } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { | ||
953 | unsigned int i; | ||
954 | |||
955 | verbose("Device %s OK: offered", dev->name); | ||
956 | for (i = 0; i < dev->desc->feature_len; i++) | ||
957 | verbose(" %08x", get_feature_bits(dev)[i]); | ||
958 | verbose(", accepted"); | ||
959 | for (i = 0; i < dev->desc->feature_len; i++) | ||
960 | verbose(" %08x", get_feature_bits(dev) | ||
961 | [dev->desc->feature_len+i]); | ||
962 | |||
963 | if (dev->ready) | ||
964 | dev->ready(dev); | ||
946 | } | 965 | } |
947 | } | 966 | } |
948 | 967 | ||
@@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr) | |||
954 | 973 | ||
955 | /* Check each device and virtqueue. */ | 974 | /* Check each device and virtqueue. */ |
956 | for (i = devices.dev; i; i = i->next) { | 975 | for (i = devices.dev; i; i = i->next) { |
957 | /* Notifications to device descriptors reset the device. */ | 976 | /* Notifications to device descriptors update device status. */ |
958 | if (from_guest_phys(addr) == i->desc) { | 977 | if (from_guest_phys(addr) == i->desc) { |
959 | reset_device(i); | 978 | update_device_status(i); |
960 | return; | 979 | return; |
961 | } | 980 | } |
962 | 981 | ||
@@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd, | |||
1170 | dev->handle_input = handle_input; | 1189 | dev->handle_input = handle_input; |
1171 | dev->name = name; | 1190 | dev->name = name; |
1172 | dev->vq = NULL; | 1191 | dev->vq = NULL; |
1192 | dev->ready = NULL; | ||
1173 | 1193 | ||
1174 | /* Append to device list. Prepending to a single-linked list is | 1194 | /* Append to device list. Prepending to a single-linked list is |
1175 | * easier, but the user expects the devices to be arranged on the bus | 1195 | * easier, but the user expects the devices to be arranged on the bus |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 7a643a6ee9a1..8080249957af 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
@@ -144,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev) | |||
144 | return to_lgdev(vdev)->desc->status; | 144 | return to_lgdev(vdev)->desc->status; |
145 | } | 145 | } |
146 | 146 | ||
147 | /* To notify on status updates, we (ab)use the NOTIFY hypercall, with the | ||
148 | * descriptor address of the device. A zero status means "reset". */ | ||
149 | static void set_status(struct virtio_device *vdev, u8 status) | ||
150 | { | ||
151 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | ||
152 | |||
153 | /* We set the status. */ | ||
154 | to_lgdev(vdev)->desc->status = status; | ||
155 | hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); | ||
156 | } | ||
157 | |||
147 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 158 | static void lg_set_status(struct virtio_device *vdev, u8 status) |
148 | { | 159 | { |
149 | BUG_ON(!status); | 160 | BUG_ON(!status); |
150 | to_lgdev(vdev)->desc->status = status; | 161 | set_status(vdev, status); |
151 | } | 162 | } |
152 | 163 | ||
153 | /* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor | ||
154 | * address of the device. The Host will zero the status and all the | ||
155 | * features. */ | ||
156 | static void lg_reset(struct virtio_device *vdev) | 164 | static void lg_reset(struct virtio_device *vdev) |
157 | { | 165 | { |
158 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | 166 | set_status(vdev, 0); |
159 | |||
160 | hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); | ||
161 | } | 167 | } |
162 | 168 | ||
163 | /* | 169 | /* |