diff options
-rw-r--r-- | Documentation/virtual/lguest/lguest.c | 25 | ||||
-rw-r--r-- | drivers/lguest/lguest_device.c | 37 |
2 files changed, 28 insertions, 34 deletions
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c index e3b9bb7a644..80261d34da3 100644 --- a/Documentation/virtual/lguest/lguest.c +++ b/Documentation/virtual/lguest/lguest.c | |||
@@ -1095,9 +1095,10 @@ static void update_device_status(struct device *dev) | |||
1095 | warnx("Device %s configuration FAILED", dev->name); | 1095 | warnx("Device %s configuration FAILED", dev->name); |
1096 | if (dev->running) | 1096 | if (dev->running) |
1097 | reset_device(dev); | 1097 | reset_device(dev); |
1098 | } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { | 1098 | } else { |
1099 | if (!dev->running) | 1099 | if (dev->running) |
1100 | start_device(dev); | 1100 | err(1, "Device %s features finalized twice", dev->name); |
1101 | start_device(dev); | ||
1101 | } | 1102 | } |
1102 | } | 1103 | } |
1103 | 1104 | ||
@@ -1122,25 +1123,11 @@ static void handle_output(unsigned long addr) | |||
1122 | return; | 1123 | return; |
1123 | } | 1124 | } |
1124 | 1125 | ||
1125 | /* | 1126 | /* Devices should not be used before features are finalized. */ |
1126 | * Devices *can* be used before status is set to DRIVER_OK. | ||
1127 | * The original plan was that they would never do this: they | ||
1128 | * would always finish setting up their status bits before | ||
1129 | * actually touching the virtqueues. In practice, we allowed | ||
1130 | * them to, and they do (eg. the disk probes for partition | ||
1131 | * tables as part of initialization). | ||
1132 | * | ||
1133 | * If we see this, we start the device: once it's running, we | ||
1134 | * expect the device to catch all the notifications. | ||
1135 | */ | ||
1136 | for (vq = i->vq; vq; vq = vq->next) { | 1127 | for (vq = i->vq; vq; vq = vq->next) { |
1137 | if (addr != vq->config.pfn*getpagesize()) | 1128 | if (addr != vq->config.pfn*getpagesize()) |
1138 | continue; | 1129 | continue; |
1139 | if (i->running) | 1130 | errx(1, "Notification on %s before setup!", i->name); |
1140 | errx(1, "Notification on running %s", i->name); | ||
1141 | /* This just calls create_thread() for each virtqueue */ | ||
1142 | start_device(i); | ||
1143 | return; | ||
1144 | } | 1131 | } |
1145 | } | 1132 | } |
1146 | 1133 | ||
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 69c84a1d88e..5289ffa2e50 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
@@ -109,6 +109,17 @@ static u32 lg_get_features(struct virtio_device *vdev) | |||
109 | } | 109 | } |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * To notify on reset or feature finalization, we (ab)use the NOTIFY | ||
113 | * hypercall, with the descriptor address of the device. | ||
114 | */ | ||
115 | static void status_notify(struct virtio_device *vdev) | ||
116 | { | ||
117 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | ||
118 | |||
119 | hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0); | ||
120 | } | ||
121 | |||
122 | /* | ||
112 | * The virtio core takes the features the Host offers, and copies the ones | 123 | * The virtio core takes the features the Host offers, and copies the ones |
113 | * supported by the driver into the vdev->features array. Once that's all | 124 | * supported by the driver into the vdev->features array. Once that's all |
114 | * sorted out, this routine is called so we can tell the Host which features we | 125 | * sorted out, this routine is called so we can tell the Host which features we |
@@ -135,6 +146,9 @@ static void lg_finalize_features(struct virtio_device *vdev) | |||
135 | if (test_bit(i, vdev->features)) | 146 | if (test_bit(i, vdev->features)) |
136 | out_features[i / 8] |= (1 << (i % 8)); | 147 | out_features[i / 8] |= (1 << (i % 8)); |
137 | } | 148 | } |
149 | |||
150 | /* Tell Host we've finished with this device's feature negotiation */ | ||
151 | status_notify(vdev); | ||
138 | } | 152 | } |
139 | 153 | ||
140 | /* Once they've found a field, getting a copy of it is easy. */ | 154 | /* Once they've found a field, getting a copy of it is easy. */ |
@@ -168,28 +182,21 @@ static u8 lg_get_status(struct virtio_device *vdev) | |||
168 | return to_lgdev(vdev)->desc->status; | 182 | return to_lgdev(vdev)->desc->status; |
169 | } | 183 | } |
170 | 184 | ||
171 | /* | ||
172 | * To notify on status updates, we (ab)use the NOTIFY hypercall, with the | ||
173 | * descriptor address of the device. A zero status means "reset". | ||
174 | */ | ||
175 | static void set_status(struct virtio_device *vdev, u8 status) | ||
176 | { | ||
177 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | ||
178 | |||
179 | /* We set the status. */ | ||
180 | to_lgdev(vdev)->desc->status = status; | ||
181 | hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0); | ||
182 | } | ||
183 | |||
184 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 185 | static void lg_set_status(struct virtio_device *vdev, u8 status) |
185 | { | 186 | { |
186 | BUG_ON(!status); | 187 | BUG_ON(!status); |
187 | set_status(vdev, status); | 188 | to_lgdev(vdev)->desc->status = status; |
189 | |||
190 | /* Tell Host immediately if we failed. */ | ||
191 | if (status & VIRTIO_CONFIG_S_FAILED) | ||
192 | status_notify(vdev); | ||
188 | } | 193 | } |
189 | 194 | ||
190 | static void lg_reset(struct virtio_device *vdev) | 195 | static void lg_reset(struct virtio_device *vdev) |
191 | { | 196 | { |
192 | set_status(vdev, 0); | 197 | /* 0 status means "reset" */ |
198 | to_lgdev(vdev)->desc->status = 0; | ||
199 | status_notify(vdev); | ||
193 | } | 200 | } |
194 | 201 | ||
195 | /* | 202 | /* |